diff options
Diffstat (limited to 'arch/x86/vdso/vma.c')
-rw-r--r-- | arch/x86/vdso/vma.c | 58 |
1 files changed, 39 insertions, 19 deletions
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 7abd2be0f9b..316fbca3490 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c | |||
@@ -14,41 +14,61 @@ | |||
14 | #include <asm/vgtod.h> | 14 | #include <asm/vgtod.h> |
15 | #include <asm/proto.h> | 15 | #include <asm/proto.h> |
16 | #include <asm/vdso.h> | 16 | #include <asm/vdso.h> |
17 | #include <asm/page.h> | ||
17 | 18 | ||
18 | unsigned int __read_mostly vdso_enabled = 1; | 19 | unsigned int __read_mostly vdso_enabled = 1; |
19 | 20 | ||
20 | extern char vdso_start[], vdso_end[]; | 21 | extern char vdso_start[], vdso_end[]; |
21 | extern unsigned short vdso_sync_cpuid; | 22 | extern unsigned short vdso_sync_cpuid; |
22 | 23 | ||
23 | static struct page **vdso_pages; | 24 | extern struct page *vdso_pages[]; |
24 | static unsigned vdso_size; | 25 | static unsigned vdso_size; |
25 | 26 | ||
26 | static int __init init_vdso_vars(void) | 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) | ||
27 | { | 59 | { |
28 | int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; | 60 | int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; |
29 | int i; | 61 | int i; |
30 | 62 | ||
63 | patch_vdso(vdso_start, vdso_end - vdso_start); | ||
64 | |||
31 | vdso_size = npages << PAGE_SHIFT; | 65 | vdso_size = npages << PAGE_SHIFT; |
32 | vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL); | 66 | for (i = 0; i < npages; i++) |
33 | if (!vdso_pages) | 67 | vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE); |
34 | goto oom; | ||
35 | for (i = 0; i < npages; i++) { | ||
36 | struct page *p; | ||
37 | p = alloc_page(GFP_KERNEL); | ||
38 | if (!p) | ||
39 | goto oom; | ||
40 | vdso_pages[i] = p; | ||
41 | copy_page(page_address(p), vdso_start + i*PAGE_SIZE); | ||
42 | } | ||
43 | 68 | ||
44 | return 0; | 69 | return 0; |
45 | |||
46 | oom: | ||
47 | printk("Cannot allocate vdso\n"); | ||
48 | vdso_enabled = 0; | ||
49 | return -ENOMEM; | ||
50 | } | 70 | } |
51 | subsys_initcall(init_vdso_vars); | 71 | subsys_initcall(init_vdso); |
52 | 72 | ||
53 | struct linux_binprm; | 73 | struct linux_binprm; |
54 | 74 | ||