diff options
Diffstat (limited to 'arch')
-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 | } | ||