| Richard Weinberger | f1c2bb8 | 2011-07-25 17:12:54 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | 
|  | 3 | * | 
|  | 4 | * This program is free software; you can redistribute it and/or modify | 
|  | 5 | * it under the terms of the GNU General Public License version 2 as | 
|  | 6 | * published by the Free Software Foundation. | 
|  | 7 | */ | 
|  | 8 |  | 
|  | 9 | #include <linux/slab.h> | 
|  | 10 | #include <linux/sched.h> | 
|  | 11 | #include <linux/mm.h> | 
|  | 12 | #include <asm/page.h> | 
|  | 13 | #include <linux/init.h> | 
|  | 14 |  | 
|  | 15 | unsigned int __read_mostly vdso_enabled = 1; | 
|  | 16 | unsigned long um_vdso_addr; | 
|  | 17 |  | 
|  | 18 | extern unsigned long task_size; | 
|  | 19 | extern char vdso_start[], vdso_end[]; | 
|  | 20 |  | 
|  | 21 | static struct page **vdsop; | 
|  | 22 |  | 
|  | 23 | static int __init init_vdso(void) | 
|  | 24 | { | 
|  | 25 | struct page *um_vdso; | 
|  | 26 |  | 
|  | 27 | BUG_ON(vdso_end - vdso_start > PAGE_SIZE); | 
|  | 28 |  | 
|  | 29 | um_vdso_addr = task_size - PAGE_SIZE; | 
|  | 30 |  | 
| Dave Jones | 0d65ede | 2011-10-24 18:15:32 -0400 | [diff] [blame] | 31 | vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL); | 
| Richard Weinberger | f1c2bb8 | 2011-07-25 17:12:54 -0700 | [diff] [blame] | 32 | if (!vdsop) | 
|  | 33 | goto oom; | 
|  | 34 |  | 
|  | 35 | um_vdso = alloc_page(GFP_KERNEL); | 
|  | 36 | if (!um_vdso) { | 
|  | 37 | kfree(vdsop); | 
|  | 38 |  | 
|  | 39 | goto oom; | 
|  | 40 | } | 
|  | 41 |  | 
|  | 42 | copy_page(page_address(um_vdso), vdso_start); | 
|  | 43 | *vdsop = um_vdso; | 
|  | 44 |  | 
|  | 45 | return 0; | 
|  | 46 |  | 
|  | 47 | oom: | 
|  | 48 | printk(KERN_ERR "Cannot allocate vdso\n"); | 
|  | 49 | vdso_enabled = 0; | 
|  | 50 |  | 
|  | 51 | return -ENOMEM; | 
|  | 52 | } | 
|  | 53 | subsys_initcall(init_vdso); | 
|  | 54 |  | 
|  | 55 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | 
|  | 56 | { | 
|  | 57 | int err; | 
|  | 58 | struct mm_struct *mm = current->mm; | 
|  | 59 |  | 
|  | 60 | if (!vdso_enabled) | 
|  | 61 | return 0; | 
|  | 62 |  | 
|  | 63 | down_write(&mm->mmap_sem); | 
|  | 64 |  | 
|  | 65 | err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE, | 
|  | 66 | VM_READ|VM_EXEC| | 
|  | 67 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| | 
|  | 68 | VM_ALWAYSDUMP, | 
|  | 69 | vdsop); | 
|  | 70 |  | 
|  | 71 | up_write(&mm->mmap_sem); | 
|  | 72 |  | 
|  | 73 | return err; | 
|  | 74 | } |