vdso32-setup.c 6.2 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 43
#ifdef CONFIG_X86_64
#define vdso_enabled			sysctl_vsyscall32
#define arch_setup_additional_pages	syscall32_setup_pages
#endif

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

static int __init vdso_setup(char *s)
{
	vdso_enabled = simple_strtoul(s, NULL, 0);

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

57 58 59
	return 1;
}

R
Roland McGrath 已提交
60 61 62 63 64 65
/*
 * 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.
 */
__setup("vdso32=", vdso_setup);
66

R
Roland McGrath 已提交
67 68 69 70 71
#ifdef CONFIG_X86_32
__setup_param("vdso=", vdso32_setup, vdso_setup, 0);

EXPORT_SYMBOL_GPL(vdso_enabled);
#endif
L
Linus Torvalds 已提交
72

73
static struct page **vdso32_pages;
74
static unsigned vdso32_size;
R
Roland McGrath 已提交
75 76 77

#ifdef CONFIG_X86_64

78
#define	vdso32_sysenter()	(boot_cpu_has(X86_FEATURE_SYSENTER32))
79
#define	vdso32_syscall()	(boot_cpu_has(X86_FEATURE_SYSCALL32))
R
Roland McGrath 已提交
80 81 82 83 84 85

/* May not be __init: called during resume */
void syscall32_cpu_init(void)
{
	/* Load these always in case some future AMD CPU supports
	   SYSENTER from compat mode too. */
86 87 88
	wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
	wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
	wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
R
Roland McGrath 已提交
89 90 91 92 93 94 95

	wrmsrl(MSR_CSTAR, ia32_cstar_target);
}

#else  /* CONFIG_X86_32 */

#define vdso32_sysenter()	(boot_cpu_has(X86_FEATURE_SEP))
96
#define vdso32_syscall()	(0)
R
Roland McGrath 已提交
97

L
Li Shaohua 已提交
98
void enable_sep_cpu(void)
L
Linus Torvalds 已提交
99 100 101 102
{
	int cpu = get_cpu();
	struct tss_struct *tss = &per_cpu(init_tss, cpu);

L
Li Shaohua 已提交
103 104 105 106 107
	if (!boot_cpu_has(X86_FEATURE_SEP)) {
		put_cpu();
		return;
	}

108
	tss->x86_tss.ss1 = __KERNEL_CS;
109
	tss->x86_tss.sp1 = sizeof(struct tss_struct) + (unsigned long) tss;
L
Linus Torvalds 已提交
110
	wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
111
	wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.sp1, 0);
R
Roland McGrath 已提交
112
	wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) ia32_sysenter_target, 0);
L
Linus Torvalds 已提交
113 114 115
	put_cpu();	
}

R
Roland McGrath 已提交
116 117
#endif	/* CONFIG_X86_64 */

118
int __init sysenter_setup(void)
L
Linus Torvalds 已提交
119
{
120 121
	char *vdso32_start, *vdso32_end;
	int npages, i;
L
Linus Torvalds 已提交
122

123
#ifdef CONFIG_COMPAT
124
	if (vdso32_syscall()) {
125 126 127 128 129 130 131 132 133
		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;
134
	} else {
135 136 137
		vdso32_start = vdso32_int80_start;
		vdso32_end = vdso32_int80_end;
		vdso32_pages = vdso32_int80_pages;
L
Linus Torvalds 已提交
138 139
	}

140 141 142 143
	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);
144

145
	patch_vdso32(vdso32_start, vdso32_size);
L
Linus Torvalds 已提交
146 147 148

	return 0;
}
149 150

/* Setup a VMA at program startup for the vsyscall page */
151
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
152 153 154
{
	struct mm_struct *mm = current->mm;
	unsigned long addr;
155
	int ret = 0;
156
	struct vm_area_struct *vma;
157

H
H. J. Lu 已提交
158 159
#ifdef CONFIG_X86_X32_ABI
	if (test_thread_flag(TIF_X32))
160
		return x32_setup_additional_pages(bprm, uses_interp);
H
H. J. Lu 已提交
161 162
#endif

163
	if (vdso_enabled != 1)  /* Other values all mean "disabled" */
164 165
		return 0;

166 167
	down_write(&mm->mmap_sem);

168
	addr = get_unmapped_area(NULL, 0, vdso32_size + VDSO_OFFSET(VDSO_PREV_PAGES), 0, 0);
169 170 171
	if (IS_ERR_VALUE(addr)) {
		ret = addr;
		goto up_fail;
R
Roland McGrath 已提交
172
	}
173

174 175
	addr += VDSO_OFFSET(VDSO_PREV_PAGES);

176 177
	current->mm->context.vdso = (void *)addr;

178 179 180
	/*
	 * MAYWRITE to allow gdb to COW and set breakpoints
	 */
181 182
	ret = install_special_mapping(mm,
			addr,
183
			vdso32_size,
184 185 186
			VM_READ|VM_EXEC|
			VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
			vdso32_pages);
187 188 189

	if (ret)
		goto up_fail;
190

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
	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

224
	current_thread_info()->sysenter_return =
R
Roland McGrath 已提交
225
		VDSO32_SYMBOL(addr, SYSENTER_RETURN);
226 227

  up_fail:
228 229 230
	if (ret)
		current->mm->context.vdso = NULL;

231
	up_write(&mm->mmap_sem);
232

233 234 235
	return ret;
}

R
Roland McGrath 已提交
236 237
#ifdef CONFIG_X86_64

238
subsys_initcall(sysenter_setup);
R
Roland McGrath 已提交
239

R
Roland McGrath 已提交
240 241 242 243
#ifdef CONFIG_SYSCTL
/* Register vsyscall32 into the ABI table */
#include <linux/sysctl.h>

244
static struct ctl_table abi_table2[] = {
R
Roland McGrath 已提交
245 246 247 248 249 250 251 252 253 254
	{
		.procname	= "vsyscall32",
		.data		= &sysctl_vsyscall32,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec
	},
	{}
};

255
static struct ctl_table abi_root_table2[] = {
R
Roland McGrath 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
	{
		.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 已提交
272 273
#else  /* CONFIG_X86_32 */

274 275 276 277 278 279 280
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;
}

281
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
282 283 284 285
{
	return NULL;
}

286
int in_gate_area(struct mm_struct *mm, unsigned long addr)
287
{
288
	return 0;
289 290
}

291
int in_gate_area_no_mm(unsigned long addr)
292 293 294
{
	return 0;
}
R
Roland McGrath 已提交
295 296

#endif	/* CONFIG_X86_64 */