2 * Copyright 2012 Tilera Corporation. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
15 #include <linux/binfmts.h>
16 #include <linux/compat.h>
17 #include <linux/elf.h>
19 #include <linux/pagemap.h>
23 #include <asm/sections.h>
27 /* The alignment of the vDSO. */
28 #define VDSO_ALIGNMENT PAGE_SIZE
31 static unsigned int vdso_pages
;
32 static struct page
**vdso_pagelist
;
35 static unsigned int vdso32_pages
;
36 static struct page
**vdso32_pagelist
;
38 static int vdso_ready
;
44 struct vdso_data data
;
46 } vdso_data_store __page_aligned_data
;
48 struct vdso_data
*vdso_data
= &vdso_data_store
.data
;
50 static unsigned int __read_mostly vdso_enabled
= 1;
52 static struct page
**vdso_setup(void *vdso_kbase
, unsigned int pages
)
55 struct page
**pagelist
;
57 pagelist
= kzalloc(sizeof(struct page
*) * (pages
+ 1), GFP_KERNEL
);
58 BUG_ON(pagelist
== NULL
);
59 for (i
= 0; i
< pages
- 1; i
++) {
60 struct page
*pg
= virt_to_page(vdso_kbase
+ i
*PAGE_SIZE
);
61 ClearPageReserved(pg
);
64 pagelist
[pages
- 1] = virt_to_page(vdso_data
);
65 pagelist
[pages
] = NULL
;
70 static int __init
vdso_init(void)
72 int data_pages
= sizeof(vdso_data_store
) >> PAGE_SHIFT
;
75 * We can disable vDSO support generally, but we need to retain
76 * one page to support the two-bundle (16-byte) rt_sigreturn path.
79 size_t offset
= (unsigned long)&__vdso_rt_sigreturn
;
80 static struct page
*sigret_page
;
81 sigret_page
= alloc_page(GFP_KERNEL
| __GFP_ZERO
);
82 BUG_ON(sigret_page
== NULL
);
83 vdso_pagelist
= &sigret_page
;
85 BUG_ON(offset
>= PAGE_SIZE
);
86 memcpy(page_address(sigret_page
) + offset
,
87 vdso_start
+ offset
, 16);
89 vdso32_pages
= vdso_pages
;
90 vdso32_pagelist
= vdso_pagelist
;
96 vdso_pages
= (vdso_end
- vdso_start
) >> PAGE_SHIFT
;
97 vdso_pages
+= data_pages
;
98 vdso_pagelist
= vdso_setup(vdso_start
, vdso_pages
);
101 vdso32_pages
= (vdso32_end
- vdso32_start
) >> PAGE_SHIFT
;
102 vdso32_pages
+= data_pages
;
103 vdso32_pagelist
= vdso_setup(vdso32_start
, vdso32_pages
);
111 arch_initcall(vdso_init
);
113 const char *arch_vma_name(struct vm_area_struct
*vma
)
115 if (vma
->vm_mm
&& vma
->vm_start
== VDSO_BASE
)
118 if (vma
->vm_start
== MEM_USER_INTRPT
)
124 struct vm_area_struct
*get_gate_vma(struct mm_struct
*mm
)
129 int in_gate_area(struct mm_struct
*mm
, unsigned long address
)
134 int in_gate_area_no_mm(unsigned long address
)
139 int setup_vdso_pages(void)
141 struct page
**pagelist
;
143 struct mm_struct
*mm
= current
->mm
;
144 unsigned long vdso_base
= 0;
150 mm
->context
.vdso_base
= 0;
152 pagelist
= vdso_pagelist
;
155 if (is_compat_task()) {
156 pagelist
= vdso32_pagelist
;
157 pages
= vdso32_pages
;
162 * vDSO has a problem and was disabled, just don't "enable" it for the
168 vdso_base
= get_unmapped_area(NULL
, vdso_base
,
169 (pages
<< PAGE_SHIFT
) +
170 ((VDSO_ALIGNMENT
- 1) & PAGE_MASK
),
172 if (IS_ERR_VALUE(vdso_base
)) {
177 /* Add required alignment. */
178 vdso_base
= ALIGN(vdso_base
, VDSO_ALIGNMENT
);
181 * Put vDSO base into mm struct. We need to do this before calling
182 * install_special_mapping or the perf counter mmap tracking code
183 * will fail to recognise it as a vDSO (since arch_vma_name fails).
185 mm
->context
.vdso_base
= vdso_base
;
188 * our vma flags don't have VM_WRITE so by default, the process isn't
189 * allowed to write those pages.
190 * gdb can break that with ptrace interface, and thus trigger COW on
191 * those pages but it's then your responsibility to never do that on
192 * the "data" page of the vDSO or you'll stop getting kernel updates
193 * and your nice userland gettimeofday will be totally dead.
194 * It's fine to use that for setting breakpoints in the vDSO code
197 retval
= install_special_mapping(mm
, vdso_base
,
200 VM_MAYREAD
| VM_MAYWRITE
| VM_MAYEXEC
,
203 mm
->context
.vdso_base
= 0;
208 static __init
int vdso_func(char *s
)
210 return kstrtouint(s
, 0, &vdso_enabled
);
212 __setup("vdso=", vdso_func
);