| Richard Kuo | cd5b61d | 2011-10-31 18:41:21 -0500 | [diff] [blame] | 1 | /* | 
 | 2 |  * vDSO implementation for Hexagon | 
 | 3 |  * | 
 | 4 |  * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 
 | 5 |  * | 
 | 6 |  * This program is free software; you can redistribute it and/or modify | 
 | 7 |  * it under the terms of the GNU General Public License version 2 and | 
 | 8 |  * only version 2 as published by the Free Software Foundation. | 
 | 9 |  * | 
 | 10 |  * This program is distributed in the hope that it will be useful, | 
 | 11 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 12 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 13 |  * GNU General Public License for more details. | 
 | 14 |  * | 
 | 15 |  * You should have received a copy of the GNU General Public License | 
 | 16 |  * along with this program; if not, write to the Free Software | 
 | 17 |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 
 | 18 |  * 02110-1301, USA. | 
 | 19 |  */ | 
 | 20 |  | 
 | 21 | #include <linux/err.h> | 
 | 22 | #include <linux/mm.h> | 
 | 23 | #include <linux/vmalloc.h> | 
 | 24 |  | 
 | 25 | #include <asm/vdso.h> | 
 | 26 |  | 
 | 27 | static struct page *vdso_page; | 
 | 28 |  | 
 | 29 | /* Create a vDSO page holding the signal trampoline. | 
 | 30 |  * We want this for a non-executable stack. | 
 | 31 |  */ | 
 | 32 | static int __init vdso_init(void) | 
 | 33 | { | 
 | 34 | 	struct hexagon_vdso *vdso; | 
 | 35 |  | 
 | 36 | 	vdso_page = alloc_page(GFP_KERNEL); | 
 | 37 | 	if (!vdso_page) | 
 | 38 | 		panic("Cannot allocate vdso"); | 
 | 39 |  | 
 | 40 | 	vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL); | 
 | 41 | 	if (!vdso) | 
 | 42 | 		panic("Cannot map vdso"); | 
 | 43 | 	clear_page(vdso); | 
 | 44 |  | 
 | 45 | 	/* Install the signal trampoline; currently looks like this: | 
 | 46 | 	 *	r6 = #__NR_rt_sigreturn; | 
 | 47 | 	 *	trap0(#1); | 
 | 48 | 	 */ | 
 | 49 | 	vdso->rt_signal_trampoline[0] = __rt_sigtramp_template[0]; | 
 | 50 | 	vdso->rt_signal_trampoline[1] = __rt_sigtramp_template[1]; | 
 | 51 |  | 
 | 52 | 	vunmap(vdso); | 
 | 53 |  | 
 | 54 | 	return 0; | 
 | 55 | } | 
 | 56 | arch_initcall(vdso_init); | 
 | 57 |  | 
 | 58 | /* | 
 | 59 |  * Called from binfmt_elf.  Create a VMA for the vDSO page. | 
 | 60 |  */ | 
 | 61 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | 
 | 62 | { | 
 | 63 | 	int ret; | 
 | 64 | 	unsigned long vdso_base; | 
 | 65 | 	struct mm_struct *mm = current->mm; | 
 | 66 |  | 
 | 67 | 	down_write(&mm->mmap_sem); | 
 | 68 |  | 
 | 69 | 	/* Try to get it loaded right near ld.so/glibc. */ | 
 | 70 | 	vdso_base = STACK_TOP; | 
 | 71 |  | 
 | 72 | 	vdso_base = get_unmapped_area(NULL, vdso_base, PAGE_SIZE, 0, 0); | 
 | 73 | 	if (IS_ERR_VALUE(vdso_base)) { | 
 | 74 | 		ret = vdso_base; | 
 | 75 | 		goto up_fail; | 
 | 76 | 	} | 
 | 77 |  | 
 | 78 | 	/* MAYWRITE to allow gdb to COW and set breakpoints. */ | 
 | 79 | 	ret = install_special_mapping(mm, vdso_base, PAGE_SIZE, | 
 | 80 | 				      VM_READ|VM_EXEC| | 
 | 81 | 				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| | 
 | 82 | 				      VM_ALWAYSDUMP, | 
 | 83 | 				      &vdso_page); | 
 | 84 |  | 
 | 85 | 	if (ret) | 
 | 86 | 		goto up_fail; | 
 | 87 |  | 
 | 88 | 	mm->context.vdso = (void *)vdso_base; | 
 | 89 |  | 
 | 90 | up_fail: | 
 | 91 | 	up_write(&mm->mmap_sem); | 
 | 92 | 	return ret; | 
 | 93 | } | 
 | 94 |  | 
 | 95 | const char *arch_vma_name(struct vm_area_struct *vma) | 
 | 96 | { | 
 | 97 | 	if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) | 
 | 98 | 		return "[vdso]"; | 
 | 99 | 	return NULL; | 
 | 100 | } |