aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/vdso.c
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2010-02-18 19:13:04 -0500
committerRalf Baechle <ralf@linux-mips.org>2010-04-12 12:26:14 -0400
commitc52d0d30aef84aa8893b34e5254716c8ab5c4472 (patch)
tree0ba93eb7e305229ceb2ee04119dc7ab22b9fa33d /arch/mips/kernel/vdso.c
parent58b9e2239fa63c7c470acb4a77e9da17e6a6fa4f (diff)
MIPS: Preliminary VDSO
This is a preliminary patch to add a vdso to all user processes. Still missing are ELF headers and .eh_frame information. But it is enough to allow us to move signal trampolines off of the stack. Note that emulation of branch delay slots in the FPU emulator still requires the stack. We allocate a single page (the vdso) and write all possible signal trampolines into it. The stack is moved down by one page and the vdso is mapped into this space. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/975/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/vdso.c')
-rw-r--r--arch/mips/kernel/vdso.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
new file mode 100644
index 000000000000..b773c1112b14
--- /dev/null
+++ b/arch/mips/kernel/vdso.c
@@ -0,0 +1,112 @@
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 pr_notice("init_vdso successfull\n");
65
66 return 0;
67}
68device_initcall(init_vdso);
69
70static unsigned long vdso_addr(unsigned long start)
71{
72 return STACK_TOP;
73}
74
75int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
76{
77 int ret;
78 unsigned long addr;
79 struct mm_struct *mm = current->mm;
80
81 down_write(&mm->mmap_sem);
82
83 addr = vdso_addr(mm->start_stack);
84
85 addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0);
86 if (IS_ERR_VALUE(addr)) {
87 ret = addr;
88 goto up_fail;
89 }
90
91 ret = install_special_mapping(mm, addr, PAGE_SIZE,
92 VM_READ|VM_EXEC|
93 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
94 VM_ALWAYSDUMP,
95 &vdso_page);
96
97 if (ret)
98 goto up_fail;
99
100 mm->context.vdso = (void *)addr;
101
102up_fail:
103 up_write(&mm->mmap_sem);
104 return ret;
105}
106
107const char *arch_vma_name(struct vm_area_struct *vma)
108{
109 if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
110 return "[vdso]";
111 return NULL;
112}