diff options
| -rw-r--r-- | arch/mips/include/asm/elf.h | 4 | ||||
| -rw-r--r-- | arch/mips/include/asm/mmu.h | 5 | ||||
| -rw-r--r-- | arch/mips/include/asm/mmu_context.h | 2 | ||||
| -rw-r--r-- | arch/mips/include/asm/processor.h | 11 | ||||
| -rw-r--r-- | arch/mips/include/asm/vdso.h | 29 | ||||
| -rw-r--r-- | arch/mips/kernel/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/kernel/syscall.c | 6 | ||||
| -rw-r--r-- | arch/mips/kernel/vdso.c | 112 |
8 files changed, 165 insertions, 6 deletions
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 1184f6eea98b..ea77a42c5f8c 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h | |||
| @@ -368,4 +368,8 @@ extern const char *__elf_platform; | |||
| 368 | #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) | 368 | #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) |
| 369 | #endif | 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 | #endif /* _ASM_ELF_H */ | 375 | #endif /* _ASM_ELF_H */ |
diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h index 4063edd79623..c436138945a8 100644 --- a/arch/mips/include/asm/mmu.h +++ b/arch/mips/include/asm/mmu.h | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | #ifndef __ASM_MMU_H | 1 | #ifndef __ASM_MMU_H |
| 2 | #define __ASM_MMU_H | 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 | #endif /* __ASM_MMU_H */ | 9 | #endif /* __ASM_MMU_H */ |
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index 145bb81ccaa5..d9592733a7ba 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h | |||
| @@ -104,7 +104,7 @@ extern unsigned long smtc_asid_mask; | |||
| 104 | 104 | ||
| 105 | #endif | 105 | #endif |
| 106 | 106 | ||
| 107 | #define cpu_context(cpu, mm) ((mm)->context[cpu]) | 107 | #define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) |
| 108 | #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) | 108 | #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) |
| 109 | #define asid_cache(cpu) (cpu_data[cpu].asid_cache) | 109 | #define asid_cache(cpu) (cpu_data[cpu].asid_cache) |
| 110 | 110 | ||
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 087a8884ef06..ab387910009a 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h | |||
| @@ -33,13 +33,19 @@ extern void (*cpu_wait)(void); | |||
| 33 | 33 | ||
| 34 | extern unsigned int vced_count, vcei_count; | 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 | #ifdef CONFIG_32BIT | 42 | #ifdef CONFIG_32BIT |
| 37 | /* | 43 | /* |
| 38 | * User space process size: 2GB. This is hardcoded into a few places, | 44 | * User space process size: 2GB. This is hardcoded into a few places, |
| 39 | * so don't change it unless you know what you are doing. | 45 | * so don't change it unless you know what you are doing. |
| 40 | */ | 46 | */ |
| 41 | #define TASK_SIZE 0x7fff8000UL | 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 | * This decides where the kernel will search for a free chunk of vm | 51 | * This decides where the kernel will search for a free chunk of vm |
| @@ -59,7 +65,8 @@ extern unsigned int vced_count, vcei_count; | |||
| 59 | #define TASK_SIZE32 0x7fff8000UL | 65 | #define TASK_SIZE32 0x7fff8000UL |
| 60 | #define TASK_SIZE 0x10000000000UL | 66 | #define TASK_SIZE 0x10000000000UL |
| 61 | #define STACK_TOP \ | 67 | #define STACK_TOP \ |
| 62 | (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE) | 68 | (((test_thread_flag(TIF_32BIT_ADDR) ? \ |
| 69 | TASK_SIZE32 : TASK_SIZE) & PAGE_MASK) - SPECIAL_PAGES_SIZE) | ||
| 63 | 70 | ||
| 64 | /* | 71 | /* |
| 65 | * This decides where the kernel will search for a free chunk of vm | 72 | * This decides where the kernel will search for a free chunk of vm |
diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h new file mode 100644 index 000000000000..cca56aa40ff4 --- /dev/null +++ b/arch/mips/include/asm/vdso.h | |||
| @@ -0,0 +1,29 @@ | |||
| 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 */ | ||
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index ef20957ca14b..7a6ac501cbb5 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
| @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds | |||
| 6 | 6 | ||
| 7 | obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ | 7 | obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ |
| 8 | ptrace.o reset.o setup.o signal.o syscall.o \ | 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 | ifdef CONFIG_FUNCTION_TRACER | 11 | ifdef CONFIG_FUNCTION_TRACER |
| 12 | CFLAGS_REMOVE_ftrace.o = -pg | 12 | CFLAGS_REMOVE_ftrace.o = -pg |
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 9587abc67f35..dd81b0f87518 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c | |||
| @@ -79,7 +79,11 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | |||
| 79 | int do_color_align; | 79 | int do_color_align; |
| 80 | unsigned long task_size; | 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 | if (len > task_size) | 88 | if (len > task_size) |
| 85 | return -ENOMEM; | 89 | return -ENOMEM; |
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c new file mode 100644 index 000000000000..b773c1112b14 --- /dev/null +++ b/arch/mips/kernel/vdso.c | |||
| @@ -0,0 +1,112 @@ | |||
| 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 | } | ||
