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