linux/arch/mips/kernel/vdso.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2009, 2010 Cavium Networks, Inc.
   7 */
   8
   9
  10#include <linux/kernel.h>
  11#include <linux/err.h>
  12#include <linux/sched.h>
  13#include <linux/mm.h>
  14#include <linux/init.h>
  15#include <linux/binfmts.h>
  16#include <linux/elf.h>
  17#include <linux/vmalloc.h>
  18#include <linux/unistd.h>
  19
  20#include <asm/vdso.h>
  21#include <asm/uasm.h>
  22
  23/*
  24 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
  25 */
  26#define __NR_O32_sigreturn              4119
  27#define __NR_O32_rt_sigreturn           4193
  28#define __NR_N32_rt_sigreturn           6211
  29
  30static struct page *vdso_page;
  31
  32static void __init install_trampoline(u32 *tramp, unsigned int sigreturn)
  33{
  34        uasm_i_addiu(&tramp, 2, 0, sigreturn);  /* li v0, sigreturn */
  35        uasm_i_syscall(&tramp, 0);
  36}
  37
  38static int __init init_vdso(void)
  39{
  40        struct mips_vdso *vdso;
  41
  42        vdso_page = alloc_page(GFP_KERNEL);
  43        if (!vdso_page)
  44                panic("Cannot allocate vdso");
  45
  46        vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL);
  47        if (!vdso)
  48                panic("Cannot map vdso");
  49        clear_page(vdso);
  50
  51        install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn);
  52#ifdef CONFIG_32BIT
  53        install_trampoline(vdso->signal_trampoline, __NR_sigreturn);
  54#else
  55        install_trampoline(vdso->n32_rt_signal_trampoline,
  56                           __NR_N32_rt_sigreturn);
  57        install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn);
  58        install_trampoline(vdso->o32_rt_signal_trampoline,
  59                           __NR_O32_rt_sigreturn);
  60#endif
  61
  62        vunmap(vdso);
  63
  64        return 0;
  65}
  66subsys_initcall(init_vdso);
  67
  68static unsigned long vdso_addr(unsigned long start)
  69{
  70        return STACK_TOP;
  71}
  72
  73int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
  74{
  75        int ret;
  76        unsigned long addr;
  77        struct mm_struct *mm = current->mm;
  78
  79        down_write(&mm->mmap_sem);
  80
  81        addr = vdso_addr(mm->start_stack);
  82
  83        addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0);
  84        if (IS_ERR_VALUE(addr)) {
  85                ret = addr;
  86                goto up_fail;
  87        }
  88
  89        ret = install_special_mapping(mm, addr, PAGE_SIZE,
  90                                      VM_READ|VM_EXEC|
  91                                      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
  92                                      VM_ALWAYSDUMP,
  93                                      &vdso_page);
  94
  95        if (ret)
  96                goto up_fail;
  97
  98        mm->context.vdso = (void *)addr;
  99
 100up_fail:
 101        up_write(&mm->mmap_sem);
 102        return ret;
 103}
 104
 105const char *arch_vma_name(struct vm_area_struct *vma)
 106{
 107        if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
 108                return "[vdso]";
 109        return NULL;
 110}
 111