xhci: Add XHCI_INTEL_HOST quirk
[pandora-kernel.git] / arch / x86 / vdso / vma.c
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>
7 #include <linux/err.h>
8 #include <linux/sched.h>
9 #include <linux/slab.h>
10 #include <linux/init.h>
11 #include <linux/random.h>
12 #include <linux/elf.h>
13 #include <asm/vsyscall.h>
14 #include <asm/vgtod.h>
15 #include <asm/proto.h>
16 #include <asm/vdso.h>
17 #include <asm/page.h>
18
19 unsigned int __read_mostly vdso_enabled = 1;
20
21 extern char vdso_start[], vdso_end[];
22 extern unsigned short vdso_sync_cpuid;
23
24 extern struct page *vdso_pages[];
25 static unsigned vdso_size;
26
27 static 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
53 found:
54         alt_data = (void *)hdr + alt_sec->sh_offset;
55         apply_alternatives(alt_data, alt_data + alt_sec->sh_size);
56 }
57
58 static int __init init_vdso(void)
59 {
60         int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
61         int i;
62
63         patch_vdso(vdso_start, vdso_end - vdso_start);
64
65         vdso_size = npages << PAGE_SHIFT;
66         for (i = 0; i < npages; i++)
67                 vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);
68
69         return 0;
70 }
71 subsys_initcall(init_vdso);
72
73 struct linux_binprm;
74
75 /*
76  * Put the vdso above the (randomized) stack with another randomized
77  * offset.  This way there is no hole in the middle of address space.
78  * To save memory make sure it is still in the same PTE as the stack
79  * top.  This doesn't give that many random bits.
80  *
81  * Note that this algorithm is imperfect: the distribution of the vdso
82  * start address within a PMD is biased toward the end.
83  */
84 static unsigned long vdso_addr(unsigned long start, unsigned len)
85 {
86         unsigned long addr, end;
87         unsigned offset;
88
89         /*
90          * Round up the start address.  It can start out unaligned as a result
91          * of stack start randomization.
92          */
93         start = PAGE_ALIGN(start);
94
95         /* Round the lowest possible end address up to a PMD boundary. */
96         end = (start + len + PMD_SIZE - 1) & PMD_MASK;
97         if (end >= TASK_SIZE_MAX)
98                 end = TASK_SIZE_MAX;
99         end -= len;
100
101         if (end > start) {
102                 offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
103                 addr = start + (offset << PAGE_SHIFT);
104         } else {
105                 addr = start;
106         }
107
108         /*
109          * Forcibly align the final address in case we have a hardware
110          * issue that requires alignment for performance reasons.
111          */
112         addr = align_addr(addr, NULL, ALIGN_VDSO);
113
114         return addr;
115 }
116
117 /* Setup a VMA at program startup for the vsyscall page.
118    Not called for compat tasks */
119 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
120 {
121         struct mm_struct *mm = current->mm;
122         unsigned long addr;
123         int ret;
124
125         if (!vdso_enabled)
126                 return 0;
127
128         down_write(&mm->mmap_sem);
129         addr = vdso_addr(mm->start_stack, vdso_size);
130         addr = get_unmapped_area(NULL, addr, vdso_size, 0, 0);
131         if (IS_ERR_VALUE(addr)) {
132                 ret = addr;
133                 goto up_fail;
134         }
135
136         current->mm->context.vdso = (void *)addr;
137
138         ret = install_special_mapping(mm, addr, vdso_size,
139                                       VM_READ|VM_EXEC|
140                                       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
141                                       VM_ALWAYSDUMP,
142                                       vdso_pages);
143         if (ret) {
144                 current->mm->context.vdso = NULL;
145                 goto up_fail;
146         }
147
148 up_fail:
149         up_write(&mm->mmap_sem);
150         return ret;
151 }
152
153 static __init int vdso_setup(char *s)
154 {
155         vdso_enabled = simple_strtoul(s, NULL, 0);
156         return 0;
157 }
158 __setup("vdso=", vdso_setup);