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 int setup_vdso_pages(void)
126 struct page
**pagelist
;
128 struct mm_struct
*mm
= current
->mm
;
129 unsigned long vdso_base
= 0;
135 mm
->context
.vdso_base
= 0;
137 pagelist
= vdso_pagelist
;
140 if (is_compat_task()) {
141 pagelist
= vdso32_pagelist
;
142 pages
= vdso32_pages
;
147 * vDSO has a problem and was disabled, just don't "enable" it for the
153 vdso_base
= get_unmapped_area(NULL
, vdso_base
,
154 (pages
<< PAGE_SHIFT
) +
155 ((VDSO_ALIGNMENT
- 1) & PAGE_MASK
),
157 if (IS_ERR_VALUE(vdso_base
)) {
162 /* Add required alignment. */
163 vdso_base
= ALIGN(vdso_base
, VDSO_ALIGNMENT
);
166 * Put vDSO base into mm struct. We need to do this before calling
167 * install_special_mapping or the perf counter mmap tracking code
168 * will fail to recognise it as a vDSO (since arch_vma_name fails).
170 mm
->context
.vdso_base
= vdso_base
;
173 * our vma flags don't have VM_WRITE so by default, the process isn't
174 * allowed to write those pages.
175 * gdb can break that with ptrace interface, and thus trigger COW on
176 * those pages but it's then your responsibility to never do that on
177 * the "data" page of the vDSO or you'll stop getting kernel updates
178 * and your nice userland gettimeofday will be totally dead.
179 * It's fine to use that for setting breakpoints in the vDSO code
182 retval
= install_special_mapping(mm
, vdso_base
,
185 VM_MAYREAD
| VM_MAYWRITE
| VM_MAYEXEC
,
188 mm
->context
.vdso_base
= 0;
193 static __init
int vdso_func(char *s
)
195 return kstrtouint(s
, 0, &vdso_enabled
);
197 __setup("vdso=", vdso_func
);