xref: /openbmc/linux/arch/mips/kernel/vdso.c (revision 909af768)
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