Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Preliminary VDSO

This is a preliminary patch to add a vdso to all user processes. Still
missing are ELF headers and .eh_frame information. But it is enough to
allow us to move signal trampolines off of the stack. Note that emulation
of branch delay slots in the FPU emulator still requires the stack.

We allocate a single page (the vdso) and write all possible signal
trampolines into it. The stack is moved down by one page and the vdso is
mapped into this space.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/975/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

David Daney and committed by
Ralf Baechle
c52d0d30 58b9e223

+165 -6
+4
arch/mips/include/asm/elf.h
··· 368 368 #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) 369 369 #endif 370 370 371 + #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 372 + struct linux_binprm; 373 + extern int arch_setup_additional_pages(struct linux_binprm *bprm, 374 + int uses_interp); 371 375 #endif /* _ASM_ELF_H */
+4 -1
arch/mips/include/asm/mmu.h
··· 1 1 #ifndef __ASM_MMU_H 2 2 #define __ASM_MMU_H 3 3 4 - typedef unsigned long mm_context_t[NR_CPUS]; 4 + typedef struct { 5 + unsigned long asid[NR_CPUS]; 6 + void *vdso; 7 + } mm_context_t; 5 8 6 9 #endif /* __ASM_MMU_H */
+1 -1
arch/mips/include/asm/mmu_context.h
··· 104 104 105 105 #endif 106 106 107 - #define cpu_context(cpu, mm) ((mm)->context[cpu]) 107 + #define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) 108 108 #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) 109 109 #define asid_cache(cpu) (cpu_data[cpu].asid_cache) 110 110
+9 -2
arch/mips/include/asm/processor.h
··· 33 33 34 34 extern unsigned int vced_count, vcei_count; 35 35 36 + /* 37 + * A special page (the vdso) is mapped into all processes at the very 38 + * top of the virtual memory space. 39 + */ 40 + #define SPECIAL_PAGES_SIZE PAGE_SIZE 41 + 36 42 #ifdef CONFIG_32BIT 37 43 /* 38 44 * User space process size: 2GB. This is hardcoded into a few places, 39 45 * so don't change it unless you know what you are doing. 40 46 */ 41 47 #define TASK_SIZE 0x7fff8000UL 42 - #define STACK_TOP TASK_SIZE 48 + #define STACK_TOP ((TASK_SIZE & PAGE_MASK) - SPECIAL_PAGES_SIZE) 43 49 44 50 /* 45 51 * This decides where the kernel will search for a free chunk of vm ··· 65 59 #define TASK_SIZE32 0x7fff8000UL 66 60 #define TASK_SIZE 0x10000000000UL 67 61 #define STACK_TOP \ 68 - (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE) 62 + (((test_thread_flag(TIF_32BIT_ADDR) ? \ 63 + TASK_SIZE32 : TASK_SIZE) & PAGE_MASK) - SPECIAL_PAGES_SIZE) 69 64 70 65 /* 71 66 * This decides where the kernel will search for a free chunk of vm
+29
arch/mips/include/asm/vdso.h
··· 1 + /* 2 + * This file is subject to the terms and conditions of the GNU General Public 3 + * License. See the file "COPYING" in the main directory of this archive 4 + * for more details. 5 + * 6 + * Copyright (C) 2009 Cavium Networks 7 + */ 8 + 9 + #ifndef __ASM_VDSO_H 10 + #define __ASM_VDSO_H 11 + 12 + #include <linux/types.h> 13 + 14 + 15 + #ifdef CONFIG_32BIT 16 + struct mips_vdso { 17 + u32 signal_trampoline[2]; 18 + u32 rt_signal_trampoline[2]; 19 + }; 20 + #else /* !CONFIG_32BIT */ 21 + struct mips_vdso { 22 + u32 o32_signal_trampoline[2]; 23 + u32 o32_rt_signal_trampoline[2]; 24 + u32 rt_signal_trampoline[2]; 25 + u32 n32_rt_signal_trampoline[2]; 26 + }; 27 + #endif /* CONFIG_32BIT */ 28 + 29 + #endif /* __ASM_VDSO_H */
+1 -1
arch/mips/kernel/Makefile
··· 6 6 7 7 obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ 8 8 ptrace.o reset.o setup.o signal.o syscall.o \ 9 - time.o topology.o traps.o unaligned.o watch.o 9 + time.o topology.o traps.o unaligned.o watch.o vdso.o 10 10 11 11 ifdef CONFIG_FUNCTION_TRACER 12 12 CFLAGS_REMOVE_ftrace.o = -pg
+5 -1
arch/mips/kernel/syscall.c
··· 79 79 int do_color_align; 80 80 unsigned long task_size; 81 81 82 - task_size = STACK_TOP; 82 + #ifdef CONFIG_32BIT 83 + task_size = TASK_SIZE; 84 + #else /* Must be CONFIG_64BIT*/ 85 + task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE; 86 + #endif 83 87 84 88 if (len > task_size) 85 89 return -ENOMEM;
+112
arch/mips/kernel/vdso.c
··· 1 + /* 2 + * This file is subject to the terms and conditions of the GNU General Public 3 + * License. See the file "COPYING" in the main directory of this archive 4 + * for more details. 5 + * 6 + * Copyright (C) 2009, 2010 Cavium Networks, Inc. 7 + */ 8 + 9 + 10 + #include <linux/kernel.h> 11 + #include <linux/err.h> 12 + #include <linux/sched.h> 13 + #include <linux/mm.h> 14 + #include <linux/init.h> 15 + #include <linux/binfmts.h> 16 + #include <linux/elf.h> 17 + #include <linux/vmalloc.h> 18 + #include <linux/unistd.h> 19 + 20 + #include <asm/vdso.h> 21 + #include <asm/uasm.h> 22 + 23 + /* 24 + * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 25 + */ 26 + #define __NR_O32_sigreturn 4119 27 + #define __NR_O32_rt_sigreturn 4193 28 + #define __NR_N32_rt_sigreturn 6211 29 + 30 + static struct page *vdso_page; 31 + 32 + static void __init install_trampoline(u32 *tramp, unsigned int sigreturn) 33 + { 34 + uasm_i_addiu(&tramp, 2, 0, sigreturn); /* li v0, sigreturn */ 35 + uasm_i_syscall(&tramp, 0); 36 + } 37 + 38 + static int __init init_vdso(void) 39 + { 40 + struct mips_vdso *vdso; 41 + 42 + vdso_page = alloc_page(GFP_KERNEL); 43 + if (!vdso_page) 44 + panic("Cannot allocate vdso"); 45 + 46 + vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL); 47 + if (!vdso) 48 + panic("Cannot map vdso"); 49 + clear_page(vdso); 50 + 51 + install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn); 52 + #ifdef CONFIG_32BIT 53 + install_trampoline(vdso->signal_trampoline, __NR_sigreturn); 54 + #else 55 + install_trampoline(vdso->n32_rt_signal_trampoline, 56 + __NR_N32_rt_sigreturn); 57 + install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn); 58 + install_trampoline(vdso->o32_rt_signal_trampoline, 59 + __NR_O32_rt_sigreturn); 60 + #endif 61 + 62 + vunmap(vdso); 63 + 64 + pr_notice("init_vdso successfull\n"); 65 + 66 + return 0; 67 + } 68 + device_initcall(init_vdso); 69 + 70 + static unsigned long vdso_addr(unsigned long start) 71 + { 72 + return STACK_TOP; 73 + } 74 + 75 + int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 76 + { 77 + int ret; 78 + unsigned long addr; 79 + struct mm_struct *mm = current->mm; 80 + 81 + down_write(&mm->mmap_sem); 82 + 83 + addr = vdso_addr(mm->start_stack); 84 + 85 + addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0); 86 + if (IS_ERR_VALUE(addr)) { 87 + ret = addr; 88 + goto up_fail; 89 + } 90 + 91 + ret = install_special_mapping(mm, addr, PAGE_SIZE, 92 + VM_READ|VM_EXEC| 93 + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| 94 + VM_ALWAYSDUMP, 95 + &vdso_page); 96 + 97 + if (ret) 98 + goto up_fail; 99 + 100 + mm->context.vdso = (void *)addr; 101 + 102 + up_fail: 103 + up_write(&mm->mmap_sem); 104 + return ret; 105 + } 106 + 107 + const char *arch_vma_name(struct vm_area_struct *vma) 108 + { 109 + if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) 110 + return "[vdso]"; 111 + return NULL; 112 + }