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 31 vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL); 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 vdsop); 69 70 up_write(&mm->mmap_sem); 71 72 return err; 73 } 74