aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/vsyscall/vsyscall.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2006-09-27 05:33:49 -0400
committerPaul Mundt <lethal@linux-sh.org>2006-09-27 05:33:49 -0400
commit19f9a34f87c48bbd270d617d1c986d0c23866a1a (patch)
tree19f32122aec9c16cbbf8e3331e81040a4850cb8d /arch/sh/kernel/vsyscall/vsyscall.c
parent8c12b5dc13bf8516303a8224ab4e9708b33d5b00 (diff)
sh: Initial vsyscall page support.
This implements initial support for the vsyscall page on SH. At the moment we leave it configurable due to having nommu to support from the same code base. We hook it up for the signal trampoline return at present, with more to be added later, once uClibc catches up. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/vsyscall/vsyscall.c')
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
new file mode 100644
index 000000000000..075d6cc1a2d7
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -0,0 +1,150 @@
1/*
2 * arch/sh/kernel/vsyscall.c
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * vDSO randomization
7 * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
12 */
13#include <linux/mm.h>
14#include <linux/slab.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/gfp.h>
18#include <linux/module.h>
19#include <linux/elf.h>
20
21/*
22 * Should the kernel map a VDSO page into processes and pass its
23 * address down to glibc upon exec()?
24 */
25unsigned int __read_mostly vdso_enabled = 1;
26EXPORT_SYMBOL_GPL(vdso_enabled);
27
28static int __init vdso_setup(char *s)
29{
30 vdso_enabled = simple_strtoul(s, NULL, 0);
31 return 1;
32}
33__setup("vdso=", vdso_setup);
34
35/*
36 * These symbols are defined by vsyscall.o to mark the bounds
37 * of the ELF DSO images included therein.
38 */
39extern const char vsyscall_trapa_start, vsyscall_trapa_end;
40static void *syscall_page;
41
42int __init vsyscall_init(void)
43{
44 syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
45
46 /*
47 * XXX: Map this page to a fixmap entry if we get around
48 * to adding the page to ELF core dumps
49 */
50
51 memcpy(syscall_page,
52 &vsyscall_trapa_start,
53 &vsyscall_trapa_end - &vsyscall_trapa_start);
54
55 return 0;
56}
57
58static struct page *syscall_vma_nopage(struct vm_area_struct *vma,
59 unsigned long address, int *type)
60{
61 unsigned long offset = address - vma->vm_start;
62 struct page *page;
63
64 if (address < vma->vm_start || address > vma->vm_end)
65 return NOPAGE_SIGBUS;
66
67 page = virt_to_page(syscall_page + offset);
68
69 get_page(page);
70
71 return page;
72}
73
74/* Prevent VMA merging */
75static void syscall_vma_close(struct vm_area_struct *vma)
76{
77}
78
79static struct vm_operations_struct syscall_vm_ops = {
80 .nopage = syscall_vma_nopage,
81 .close = syscall_vma_close,
82};
83
84/* Setup a VMA at program startup for the vsyscall page */
85int arch_setup_additional_pages(struct linux_binprm *bprm,
86 int executable_stack)
87{
88 struct vm_area_struct *vma;
89 struct mm_struct *mm = current->mm;
90 unsigned long addr;
91 int ret;
92
93 down_write(&mm->mmap_sem);
94 addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
95 if (IS_ERR_VALUE(addr)) {
96 ret = addr;
97 goto up_fail;
98 }
99
100 vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
101 if (!vma) {
102 ret = -ENOMEM;
103 goto up_fail;
104 }
105
106 vma->vm_start = addr;
107 vma->vm_end = addr + PAGE_SIZE;
108 /* MAYWRITE to allow gdb to COW and set breakpoints */
109 vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
110 vma->vm_flags |= mm->def_flags;
111 vma->vm_page_prot = protection_map[vma->vm_flags & 7];
112 vma->vm_ops = &syscall_vm_ops;
113 vma->vm_mm = mm;
114
115 ret = insert_vm_struct(mm, vma);
116 if (unlikely(ret)) {
117 kmem_cache_free(vm_area_cachep, vma);
118 goto up_fail;
119 }
120
121 current->mm->context.vdso = (void *)addr;
122
123 mm->total_vm++;
124up_fail:
125 up_write(&mm->mmap_sem);
126 return ret;
127}
128
129const char *arch_vma_name(struct vm_area_struct *vma)
130{
131 if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
132 return "[vdso]";
133
134 return NULL;
135}
136
137struct vm_area_struct *get_gate_vma(struct task_struct *task)
138{
139 return NULL;
140}
141
142int in_gate_area(struct task_struct *task, unsigned long address)
143{
144 return 0;
145}
146
147int in_gate_area_no_task(unsigned long address)
148{
149 return 0;
150}