]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - arch/x86/vdso/vma.c
Merge tag 'cleanup2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[mirror_ubuntu-artful-kernel.git] / arch / x86 / vdso / vma.c
CommitLineData
2aae950b
AK
1/*
2 * Set up the VMAs to tell the VM about the vDSO.
3 * Copyright 2007 Andi Kleen, SUSE Labs.
4 * Subject to the GPL, v.2
5 */
6#include <linux/mm.h>
4e950f6f 7#include <linux/err.h>
2aae950b 8#include <linux/sched.h>
5a0e3ad6 9#include <linux/slab.h>
2aae950b
AK
10#include <linux/init.h>
11#include <linux/random.h>
3fa89ca7 12#include <linux/elf.h>
2aae950b
AK
13#include <asm/vsyscall.h>
14#include <asm/vgtod.h>
15#include <asm/proto.h>
7f3646aa 16#include <asm/vdso.h>
aafade24 17#include <asm/page.h>
2aae950b 18
e6b0edef 19unsigned int __read_mostly vdso_enabled = 1;
7f3646aa
RM
20
21extern char vdso_start[], vdso_end[];
2aae950b
AK
22extern unsigned short vdso_sync_cpuid;
23
aafade24 24extern struct page *vdso_pages[];
369c9920 25static unsigned vdso_size;
2aae950b 26
1b3f2a72
AL
27static void __init patch_vdso(void *vdso, size_t len)
28{
29 Elf64_Ehdr *hdr = vdso;
30 Elf64_Shdr *sechdrs, *alt_sec = 0;
31 char *secstrings;
32 void *alt_data;
33 int i;
34
35 BUG_ON(len < sizeof(Elf64_Ehdr));
36 BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0);
37
38 sechdrs = (void *)hdr + hdr->e_shoff;
39 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
40
41 for (i = 1; i < hdr->e_shnum; i++) {
42 Elf64_Shdr *shdr = &sechdrs[i];
43 if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) {
44 alt_sec = shdr;
45 goto found;
46 }
47 }
48
49 /* If we get here, it's probably a bug. */
50 pr_warning("patch_vdso: .altinstructions not found\n");
51 return; /* nothing to patch */
52
53found:
54 alt_data = (void *)hdr + alt_sec->sh_offset;
55 apply_alternatives(alt_data, alt_data + alt_sec->sh_size);
56}
57
aafade24 58static int __init init_vdso(void)
2aae950b
AK
59{
60 int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
61 int i;
2aae950b 62
1b3f2a72
AL
63 patch_vdso(vdso_start, vdso_end - vdso_start);
64
369c9920 65 vdso_size = npages << PAGE_SHIFT;
aafade24
AL
66 for (i = 0; i < npages; i++)
67 vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);
2aae950b 68
2aae950b 69 return 0;
2aae950b 70}
aafade24 71subsys_initcall(init_vdso);
2aae950b
AK
72
73struct linux_binprm;
74
75/* Put the vdso above the (randomized) stack with another randomized offset.
76 This way there is no hole in the middle of address space.
77 To save memory make sure it is still in the same PTE as the stack top.
78 This doesn't give that many random bits */
79static unsigned long vdso_addr(unsigned long start, unsigned len)
80{
81 unsigned long addr, end;
82 unsigned offset;
83 end = (start + PMD_SIZE - 1) & PMD_MASK;
d9517346
IM
84 if (end >= TASK_SIZE_MAX)
85 end = TASK_SIZE_MAX;
2aae950b
AK
86 end -= len;
87 /* This loses some more bits than a modulo, but is cheaper */
88 offset = get_random_int() & (PTRS_PER_PTE - 1);
89 addr = start + (offset << PAGE_SHIFT);
90 if (addr >= end)
91 addr = end;
dfb09f9b
BP
92
93 /*
94 * page-align it here so that get_unmapped_area doesn't
95 * align it wrongfully again to the next page. addr can come in 4K
96 * unaligned here as a result of stack start randomization.
97 */
98 addr = PAGE_ALIGN(addr);
99 addr = align_addr(addr, NULL, ALIGN_VDSO);
100
2aae950b
AK
101 return addr;
102}
103
104/* Setup a VMA at program startup for the vsyscall page.
105 Not called for compat tasks */
fc5243d9 106int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
2aae950b
AK
107{
108 struct mm_struct *mm = current->mm;
109 unsigned long addr;
110 int ret;
2aae950b
AK
111
112 if (!vdso_enabled)
113 return 0;
114
115 down_write(&mm->mmap_sem);
369c9920
JB
116 addr = vdso_addr(mm->start_stack, vdso_size);
117 addr = get_unmapped_area(NULL, addr, vdso_size, 0, 0);
2aae950b
AK
118 if (IS_ERR_VALUE(addr)) {
119 ret = addr;
120 goto up_fail;
121 }
122
f7b6eb3f
PZ
123 current->mm->context.vdso = (void *)addr;
124
369c9920 125 ret = install_special_mapping(mm, addr, vdso_size,
2aae950b 126 VM_READ|VM_EXEC|
909af768 127 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
2aae950b 128 vdso_pages);
f7b6eb3f
PZ
129 if (ret) {
130 current->mm->context.vdso = NULL;
2aae950b 131 goto up_fail;
f7b6eb3f 132 }
2aae950b 133
2aae950b
AK
134up_fail:
135 up_write(&mm->mmap_sem);
136 return ret;
137}
138
139static __init int vdso_setup(char *s)
140{
141 vdso_enabled = simple_strtoul(s, NULL, 0);
142 return 0;
143}
144__setup("vdso=", vdso_setup);