vdso32-setup.c 5.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 * (C) Copyright 2002 Linus Torvalds
3 4
 * Portions based on the vdso-randomization code from exec-shield:
 * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15
 *
 * This file contains the needed initializations to support sysenter.
 */

#include <linux/init.h>
#include <linux/smp.h>
#include <linux/thread_info.h>
#include <linux/sched.h>
#include <linux/gfp.h>
#include <linux/string.h>
#include <linux/elf.h>
16
#include <linux/mm.h>
A
Alexey Dobriyan 已提交
17
#include <linux/err.h>
18
#include <linux/module.h>
19
#include <linux/slab.h>
L
Linus Torvalds 已提交
20 21 22 23 24

#include <asm/cpufeature.h>
#include <asm/msr.h>
#include <asm/pgtable.h>
#include <asm/unistd.h>
25
#include <asm/elf.h>
26
#include <asm/tlbflush.h>
R
Roland McGrath 已提交
27
#include <asm/vdso.h>
R
Roland McGrath 已提交
28
#include <asm/proto.h>
29 30 31
#include <asm/fixmap.h>
#include <asm/hpet.h>
#include <asm/vvar.h>
32 33

#ifdef CONFIG_COMPAT_VDSO
34
#define VDSO_DEFAULT	0
35
#else
36
#define VDSO_DEFAULT	1
37
#endif
L
Linus Torvalds 已提交
38

R
Roland McGrath 已提交
39 40 41 42
#ifdef CONFIG_X86_64
#define arch_setup_additional_pages	syscall32_setup_pages
#endif

43 44 45 46
/*
 * Should the kernel map a VDSO page into processes and pass its
 * address down to glibc upon exec()?
 */
47
unsigned int __read_mostly vdso32_enabled = VDSO_DEFAULT;
48

49
static int __init vdso32_setup(char *s)
50
{
51
	vdso32_enabled = simple_strtoul(s, NULL, 0);
52

53
	if (vdso32_enabled > 1)
54 55
		pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");

56 57 58
	return 1;
}

R
Roland McGrath 已提交
59 60 61 62 63
/*
 * For consistency, the argument vdso32=[012] affects the 32-bit vDSO
 * behavior on both 64-bit and 32-bit kernels.
 * On 32-bit kernels, vdso=[012] means the same thing.
 */
64
__setup("vdso32=", vdso32_setup);
65

R
Roland McGrath 已提交
66
#ifdef CONFIG_X86_32
67
__setup_param("vdso=", vdso_setup, vdso32_setup, 0);
R
Roland McGrath 已提交
68
#endif
L
Linus Torvalds 已提交
69

70
static struct page **vdso32_pages;
71
static unsigned vdso32_size;
R
Roland McGrath 已提交
72 73 74

#ifdef CONFIG_X86_64

75
#define	vdso32_sysenter()	(boot_cpu_has(X86_FEATURE_SYSENTER32))
76
#define	vdso32_syscall()	(boot_cpu_has(X86_FEATURE_SYSCALL32))
R
Roland McGrath 已提交
77 78 79 80

#else  /* CONFIG_X86_32 */

#define vdso32_sysenter()	(boot_cpu_has(X86_FEATURE_SEP))
81
#define vdso32_syscall()	(0)
R
Roland McGrath 已提交
82 83 84

#endif	/* CONFIG_X86_64 */

85
int __init sysenter_setup(void)
L
Linus Torvalds 已提交
86
{
87 88
	char *vdso32_start, *vdso32_end;
	int npages, i;
L
Linus Torvalds 已提交
89

90
#ifdef CONFIG_COMPAT
91
	if (vdso32_syscall()) {
92 93 94 95 96 97 98 99 100
		vdso32_start = vdso32_syscall_start;
		vdso32_end = vdso32_syscall_end;
		vdso32_pages = vdso32_syscall_pages;
	} else
#endif
	if (vdso32_sysenter()) {
		vdso32_start = vdso32_sysenter_start;
		vdso32_end = vdso32_sysenter_end;
		vdso32_pages = vdso32_sysenter_pages;
101
	} else {
102 103 104
		vdso32_start = vdso32_int80_start;
		vdso32_end = vdso32_int80_end;
		vdso32_pages = vdso32_int80_pages;
L
Linus Torvalds 已提交
105 106
	}

107 108 109 110
	npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE;
	vdso32_size = npages << PAGE_SHIFT;
	for (i = 0; i < npages; i++)
		vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE);
111

112
	patch_vdso32(vdso32_start, vdso32_size);
L
Linus Torvalds 已提交
113 114 115

	return 0;
}
116 117

/* Setup a VMA at program startup for the vsyscall page */
118
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
119 120 121
{
	struct mm_struct *mm = current->mm;
	unsigned long addr;
122
	int ret = 0;
123
	struct vm_area_struct *vma;
124

H
H. J. Lu 已提交
125 126
#ifdef CONFIG_X86_X32_ABI
	if (test_thread_flag(TIF_X32))
127
		return x32_setup_additional_pages(bprm, uses_interp);
H
H. J. Lu 已提交
128 129
#endif

130
	if (vdso32_enabled != 1)  /* Other values all mean "disabled" */
131 132
		return 0;

133 134
	down_write(&mm->mmap_sem);

135
	addr = get_unmapped_area(NULL, 0, vdso32_size + VDSO_OFFSET(VDSO_PREV_PAGES), 0, 0);
136 137 138
	if (IS_ERR_VALUE(addr)) {
		ret = addr;
		goto up_fail;
R
Roland McGrath 已提交
139
	}
140

141 142
	addr += VDSO_OFFSET(VDSO_PREV_PAGES);

143 144
	current->mm->context.vdso = (void *)addr;

145 146 147
	/*
	 * MAYWRITE to allow gdb to COW and set breakpoints
	 */
148 149
	ret = install_special_mapping(mm,
			addr,
150
			vdso32_size,
151 152 153
			VM_READ|VM_EXEC|
			VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
			vdso32_pages);
154 155 156

	if (ret)
		goto up_fail;
157

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	vma = _install_special_mapping(mm,
			addr -  VDSO_OFFSET(VDSO_PREV_PAGES),
			VDSO_OFFSET(VDSO_PREV_PAGES),
			VM_READ,
			NULL);

	if (IS_ERR(vma)) {
		ret = PTR_ERR(vma);
		goto up_fail;
	}

	ret = remap_pfn_range(vma,
		addr - VDSO_OFFSET(VDSO_VVAR_PAGE),
		__pa_symbol(&__vvar_page) >> PAGE_SHIFT,
		PAGE_SIZE,
		PAGE_READONLY);

	if (ret)
		goto up_fail;

#ifdef CONFIG_HPET_TIMER
	if (hpet_address) {
		ret = io_remap_pfn_range(vma,
			addr - VDSO_OFFSET(VDSO_HPET_PAGE),
			hpet_address >> PAGE_SHIFT,
			PAGE_SIZE,
			pgprot_noncached(PAGE_READONLY));

		if (ret)
			goto up_fail;
	}
#endif

191
	current_thread_info()->sysenter_return =
R
Roland McGrath 已提交
192
		VDSO32_SYMBOL(addr, SYSENTER_RETURN);
193 194

  up_fail:
195 196 197
	if (ret)
		current->mm->context.vdso = NULL;

198
	up_write(&mm->mmap_sem);
199

200 201 202
	return ret;
}

R
Roland McGrath 已提交
203 204
#ifdef CONFIG_X86_64

205
subsys_initcall(sysenter_setup);
R
Roland McGrath 已提交
206

R
Roland McGrath 已提交
207 208 209 210
#ifdef CONFIG_SYSCTL
/* Register vsyscall32 into the ABI table */
#include <linux/sysctl.h>

211
static struct ctl_table abi_table2[] = {
R
Roland McGrath 已提交
212 213
	{
		.procname	= "vsyscall32",
214
		.data		= &vdso32_enabled,
R
Roland McGrath 已提交
215 216 217 218 219 220 221
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec
	},
	{}
};

222
static struct ctl_table abi_root_table2[] = {
R
Roland McGrath 已提交
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
	{
		.procname = "abi",
		.mode = 0555,
		.child = abi_table2
	},
	{}
};

static __init int ia32_binfmt_init(void)
{
	register_sysctl_table(abi_root_table2);
	return 0;
}
__initcall(ia32_binfmt_init);
#endif

R
Roland McGrath 已提交
239 240
#else  /* CONFIG_X86_32 */

241 242 243 244 245 246 247
const char *arch_vma_name(struct vm_area_struct *vma)
{
	if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
		return "[vdso]";
	return NULL;
}

248
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
249 250 251 252
{
	return NULL;
}

253
int in_gate_area(struct mm_struct *mm, unsigned long addr)
254
{
255
	return 0;
256 257
}

258
int in_gate_area_no_mm(unsigned long addr)
259 260 261
{
	return 0;
}
R
Roland McGrath 已提交
262 263

#endif	/* CONFIG_X86_64 */