diff options
-rw-r--r-- | arch/sh/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/sh/kernel/process.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/signal.c | 17 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/Makefile | 36 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/vsyscall-note.S | 25 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/vsyscall-sigreturn.S | 39 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/vsyscall-syscall.S | 10 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/vsyscall-trapa.S | 42 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/vsyscall.c | 150 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/vsyscall.lds.S | 74 | ||||
-rw-r--r-- | arch/sh/mm/Kconfig | 13 | ||||
-rw-r--r-- | arch/sh/mm/init.c | 3 | ||||
-rw-r--r-- | arch/sh/mm/tlb-flush.c | 18 | ||||
-rw-r--r-- | include/asm-sh/auxvec.h | 14 | ||||
-rw-r--r-- | include/asm-sh/elf.h | 20 | ||||
-rw-r--r-- | include/asm-sh/mmu.h | 7 | ||||
-rw-r--r-- | include/asm-sh/mmu_context.h | 8 | ||||
-rw-r--r-- | include/asm-sh/page.h | 5 | ||||
-rw-r--r-- | include/asm-sh/processor.h | 6 |
19 files changed, 473 insertions, 17 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 0e2148f63e7e..5da88a43d350 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -9,6 +9,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \ | |||
9 | io.o io_generic.o sh_ksyms.o syscalls.o | 9 | io.o io_generic.o sh_ksyms.o syscalls.o |
10 | 10 | ||
11 | obj-y += cpu/ timers/ | 11 | obj-y += cpu/ timers/ |
12 | obj-$(CONFIG_VSYSCALL) += vsyscall/ | ||
12 | 13 | ||
13 | obj-$(CONFIG_SMP) += smp.o | 14 | obj-$(CONFIG_SMP) += smp.o |
14 | obj-$(CONFIG_CF_ENABLER) += cf-enabler.o | 15 | obj-$(CONFIG_CF_ENABLER) += cf-enabler.o |
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 630ec1af2483..0b1d5dd7a93b 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c | |||
@@ -355,7 +355,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne | |||
355 | else if (next->thread.ubc_pc && next->mm) { | 355 | else if (next->thread.ubc_pc && next->mm) { |
356 | int asid = 0; | 356 | int asid = 0; |
357 | #ifdef CONFIG_MMU | 357 | #ifdef CONFIG_MMU |
358 | asid |= next->mm->context & MMU_CONTEXT_ASID_MASK; | 358 | asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK; |
359 | #endif | 359 | #endif |
360 | ubc_set_tracing(asid, next->thread.ubc_pc); | 360 | ubc_set_tracing(asid, next->thread.ubc_pc); |
361 | } else { | 361 | } else { |
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 2f1c9545b49f..5213f5bc6ce0 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima | 8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | |||
12 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
13 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
14 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
@@ -21,6 +20,7 @@ | |||
21 | #include <linux/unistd.h> | 20 | #include <linux/unistd.h> |
22 | #include <linux/stddef.h> | 21 | #include <linux/stddef.h> |
23 | #include <linux/tty.h> | 22 | #include <linux/tty.h> |
23 | #include <linux/elf.h> | ||
24 | #include <linux/personality.h> | 24 | #include <linux/personality.h> |
25 | #include <linux/binfmts.h> | 25 | #include <linux/binfmts.h> |
26 | 26 | ||
@@ -29,8 +29,6 @@ | |||
29 | #include <asm/pgtable.h> | 29 | #include <asm/pgtable.h> |
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | 31 | ||
32 | #undef DEBUG | ||
33 | |||
34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 32 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
35 | 33 | ||
36 | /* | 34 | /* |
@@ -312,6 +310,11 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |||
312 | return (void __user *)((sp - frame_size) & -8ul); | 310 | return (void __user *)((sp - frame_size) & -8ul); |
313 | } | 311 | } |
314 | 312 | ||
313 | /* These symbols are defined with the addresses in the vsyscall page. | ||
314 | See vsyscall-trapa.S. */ | ||
315 | extern void __user __kernel_sigreturn; | ||
316 | extern void __user __kernel_rt_sigreturn; | ||
317 | |||
315 | static int setup_frame(int sig, struct k_sigaction *ka, | 318 | static int setup_frame(int sig, struct k_sigaction *ka, |
316 | sigset_t *set, struct pt_regs *regs) | 319 | sigset_t *set, struct pt_regs *regs) |
317 | { | 320 | { |
@@ -340,6 +343,10 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
340 | already in userspace. */ | 343 | already in userspace. */ |
341 | if (ka->sa.sa_flags & SA_RESTORER) { | 344 | if (ka->sa.sa_flags & SA_RESTORER) { |
342 | regs->pr = (unsigned long) ka->sa.sa_restorer; | 345 | regs->pr = (unsigned long) ka->sa.sa_restorer; |
346 | #ifdef CONFIG_VSYSCALL | ||
347 | } else if (likely(current->mm->context.vdso)) { | ||
348 | regs->pr = VDSO_SYM(&__kernel_sigreturn); | ||
349 | #endif | ||
343 | } else { | 350 | } else { |
344 | /* Generate return code (system call to sigreturn) */ | 351 | /* Generate return code (system call to sigreturn) */ |
345 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 352 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
@@ -416,6 +423,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
416 | already in userspace. */ | 423 | already in userspace. */ |
417 | if (ka->sa.sa_flags & SA_RESTORER) { | 424 | if (ka->sa.sa_flags & SA_RESTORER) { |
418 | regs->pr = (unsigned long) ka->sa.sa_restorer; | 425 | regs->pr = (unsigned long) ka->sa.sa_restorer; |
426 | #ifdef CONFIG_VSYSCALL | ||
427 | } else if (likely(current->mm->context.vdso)) { | ||
428 | regs->pr = VDSO_SYM(&__kernel_rt_sigreturn); | ||
429 | #endif | ||
419 | } else { | 430 | } else { |
420 | /* Generate return code (system call to rt_sigreturn) */ | 431 | /* Generate return code (system call to rt_sigreturn) */ |
421 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 432 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
diff --git a/arch/sh/kernel/vsyscall/Makefile b/arch/sh/kernel/vsyscall/Makefile new file mode 100644 index 000000000000..4bbce1cfa359 --- /dev/null +++ b/arch/sh/kernel/vsyscall/Makefile | |||
@@ -0,0 +1,36 @@ | |||
1 | obj-y += vsyscall.o vsyscall-syscall.o | ||
2 | |||
3 | $(obj)/vsyscall-syscall.o: \ | ||
4 | $(foreach F,trapa,$(obj)/vsyscall-$F.so) | ||
5 | |||
6 | # Teach kbuild about targets | ||
7 | targets += $(foreach F,trapa,vsyscall-$F.o vsyscall-$F.so) | ||
8 | targets += vsyscall-note.o vsyscall.lds | ||
9 | |||
10 | # The DSO images are built using a special linker script | ||
11 | quiet_cmd_syscall = SYSCALL $@ | ||
12 | cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ | ||
13 | -Wl,-T,$(filter-out FORCE,$^) -o $@ | ||
14 | |||
15 | export CPPFLAGS_vsyscall.lds += -P -C -Ush | ||
16 | |||
17 | vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ | ||
18 | $(call ld-option, -Wl$(comma)--hash-style=sysv) | ||
19 | |||
20 | SYSCFLAGS_vsyscall-trapa.so = $(vsyscall-flags) | ||
21 | |||
22 | $(obj)/vsyscall-trapa.so: \ | ||
23 | $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE | ||
24 | $(call if_changed,syscall) | ||
25 | |||
26 | # We also create a special relocatable object that should mirror the symbol | ||
27 | # table and layout of the linked DSO. With ld -R we can then refer to | ||
28 | # these symbols in the kernel code rather than hand-coded addresses. | ||
29 | extra-y += vsyscall-syms.o | ||
30 | $(obj)/built-in.o: $(obj)/vsyscall-syms.o | ||
31 | $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o | ||
32 | |||
33 | SYSCFLAGS_vsyscall-syms.o = -r | ||
34 | $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \ | ||
35 | $(obj)/vsyscall-trapa.o $(obj)/vsyscall-note.o FORCE | ||
36 | $(call if_changed,syscall) | ||
diff --git a/arch/sh/kernel/vsyscall/vsyscall-note.S b/arch/sh/kernel/vsyscall/vsyscall-note.S new file mode 100644 index 000000000000..d4b5be4f3d5f --- /dev/null +++ b/arch/sh/kernel/vsyscall/vsyscall-note.S | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. | ||
3 | * Here we can supply some information useful to userland. | ||
4 | */ | ||
5 | |||
6 | #include <linux/uts.h> | ||
7 | #include <linux/version.h> | ||
8 | |||
9 | #define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \ | ||
10 | .section name, flags; \ | ||
11 | .balign 4; \ | ||
12 | .long 1f - 0f; /* name length */ \ | ||
13 | .long 3f - 2f; /* data length */ \ | ||
14 | .long type; /* note type */ \ | ||
15 | 0: .asciz vendor; /* vendor name */ \ | ||
16 | 1: .balign 4; \ | ||
17 | 2: | ||
18 | |||
19 | #define ASM_ELF_NOTE_END \ | ||
20 | 3: .balign 4; /* pad out section */ \ | ||
21 | .previous | ||
22 | |||
23 | ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0) | ||
24 | .long LINUX_VERSION_CODE | ||
25 | ASM_ELF_NOTE_END | ||
diff --git a/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S new file mode 100644 index 000000000000..555a64f124ca --- /dev/null +++ b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S | |||
@@ -0,0 +1,39 @@ | |||
1 | #include <asm/unistd.h> | ||
2 | |||
3 | .text | ||
4 | .balign 32 | ||
5 | .globl __kernel_sigreturn | ||
6 | .type __kernel_sigreturn,@function | ||
7 | __kernel_sigreturn: | ||
8 | .LSTART_sigreturn: | ||
9 | mov.w 1f, r3 | ||
10 | trapa #0x10 | ||
11 | or r0, r0 | ||
12 | or r0, r0 | ||
13 | or r0, r0 | ||
14 | or r0, r0 | ||
15 | or r0, r0 | ||
16 | |||
17 | 1: .short __NR_sigreturn | ||
18 | .LEND_sigreturn: | ||
19 | .size __kernel_sigreturn,.-.LSTART_sigreturn | ||
20 | |||
21 | .balign 32 | ||
22 | .globl __kernel_rt_sigreturn | ||
23 | .type __kernel_rt_sigreturn,@function | ||
24 | __kernel_rt_sigreturn: | ||
25 | .LSTART_rt_sigreturn: | ||
26 | mov.w 1f, r3 | ||
27 | trapa #0x10 | ||
28 | or r0, r0 | ||
29 | or r0, r0 | ||
30 | or r0, r0 | ||
31 | or r0, r0 | ||
32 | or r0, r0 | ||
33 | |||
34 | 1: .short __NR_rt_sigreturn | ||
35 | .LEND_rt_sigreturn: | ||
36 | .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn | ||
37 | |||
38 | .section .eh_frame,"a",@progbits | ||
39 | .previous | ||
diff --git a/arch/sh/kernel/vsyscall/vsyscall-syscall.S b/arch/sh/kernel/vsyscall/vsyscall-syscall.S new file mode 100644 index 000000000000..c2ac7f0282b3 --- /dev/null +++ b/arch/sh/kernel/vsyscall/vsyscall-syscall.S | |||
@@ -0,0 +1,10 @@ | |||
1 | #include <linux/init.h> | ||
2 | |||
3 | __INITDATA | ||
4 | |||
5 | .globl vsyscall_trapa_start, vsyscall_trapa_end | ||
6 | vsyscall_trapa_start: | ||
7 | .incbin "arch/sh/kernel/vsyscall/vsyscall-trapa.so" | ||
8 | vsyscall_trapa_end: | ||
9 | |||
10 | __FINIT | ||
diff --git a/arch/sh/kernel/vsyscall/vsyscall-trapa.S b/arch/sh/kernel/vsyscall/vsyscall-trapa.S new file mode 100644 index 000000000000..3b6eb34c43fa --- /dev/null +++ b/arch/sh/kernel/vsyscall/vsyscall-trapa.S | |||
@@ -0,0 +1,42 @@ | |||
1 | .text | ||
2 | .globl __kernel_vsyscall | ||
3 | .type __kernel_vsyscall,@function | ||
4 | __kernel_vsyscall: | ||
5 | .LSTART_vsyscall: | ||
6 | /* XXX: We'll have to do something here once we opt to use the vDSO | ||
7 | * page for something other than the signal trampoline.. as well as | ||
8 | * fill out .eh_frame -- PFM. */ | ||
9 | .LEND_vsyscall: | ||
10 | .size __kernel_vsyscall,.-.LSTART_vsyscall | ||
11 | .previous | ||
12 | |||
13 | .section .eh_frame,"a",@progbits | ||
14 | .LCIE: | ||
15 | .ualong .LCIE_end - .LCIE_start | ||
16 | .LCIE_start: | ||
17 | .ualong 0 /* CIE ID */ | ||
18 | .byte 0x1 /* Version number */ | ||
19 | .string "zRS" /* NUL-terminated augmentation string */ | ||
20 | .uleb128 0x1 /* Code alignment factor */ | ||
21 | .sleb128 -4 /* Data alignment factor */ | ||
22 | .byte 0x11 /* Return address register column */ | ||
23 | /* Augmentation length and data (none) */ | ||
24 | .byte 0xc /* DW_CFA_def_cfa */ | ||
25 | .uleb128 0xf /* r15 */ | ||
26 | .uleb128 0x0 /* offset 0 */ | ||
27 | |||
28 | .align 2 | ||
29 | .LCIE_end: | ||
30 | |||
31 | .ualong .LFDE_end-.LFDE_start /* Length FDE */ | ||
32 | .LFDE_start: | ||
33 | .ualong .LCIE /* CIE pointer */ | ||
34 | .ualong .LSTART_vsyscall-. /* start address */ | ||
35 | .ualong .LEND_vsyscall-.LSTART_vsyscall | ||
36 | .uleb128 0 | ||
37 | .align 2 | ||
38 | .LFDE_end: | ||
39 | .previous | ||
40 | |||
41 | /* Get the common code for the sigreturn entry points */ | ||
42 | #include "vsyscall-sigreturn.S" | ||
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c new file mode 100644 index 000000000000..075d6cc1a2d7 --- /dev/null +++ b/arch/sh/kernel/vsyscall/vsyscall.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/vsyscall.c | ||
3 | * | ||
4 | * Copyright (C) 2006 Paul Mundt | ||
5 | * | ||
6 | * vDSO randomization | ||
7 | * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/gfp.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/elf.h> | ||
20 | |||
21 | /* | ||
22 | * Should the kernel map a VDSO page into processes and pass its | ||
23 | * address down to glibc upon exec()? | ||
24 | */ | ||
25 | unsigned int __read_mostly vdso_enabled = 1; | ||
26 | EXPORT_SYMBOL_GPL(vdso_enabled); | ||
27 | |||
28 | static int __init vdso_setup(char *s) | ||
29 | { | ||
30 | vdso_enabled = simple_strtoul(s, NULL, 0); | ||
31 | return 1; | ||
32 | } | ||
33 | __setup("vdso=", vdso_setup); | ||
34 | |||
35 | /* | ||
36 | * These symbols are defined by vsyscall.o to mark the bounds | ||
37 | * of the ELF DSO images included therein. | ||
38 | */ | ||
39 | extern const char vsyscall_trapa_start, vsyscall_trapa_end; | ||
40 | static void *syscall_page; | ||
41 | |||
42 | int __init vsyscall_init(void) | ||
43 | { | ||
44 | syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); | ||
45 | |||
46 | /* | ||
47 | * XXX: Map this page to a fixmap entry if we get around | ||
48 | * to adding the page to ELF core dumps | ||
49 | */ | ||
50 | |||
51 | memcpy(syscall_page, | ||
52 | &vsyscall_trapa_start, | ||
53 | &vsyscall_trapa_end - &vsyscall_trapa_start); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static struct page *syscall_vma_nopage(struct vm_area_struct *vma, | ||
59 | unsigned long address, int *type) | ||
60 | { | ||
61 | unsigned long offset = address - vma->vm_start; | ||
62 | struct page *page; | ||
63 | |||
64 | if (address < vma->vm_start || address > vma->vm_end) | ||
65 | return NOPAGE_SIGBUS; | ||
66 | |||
67 | page = virt_to_page(syscall_page + offset); | ||
68 | |||
69 | get_page(page); | ||
70 | |||
71 | return page; | ||
72 | } | ||
73 | |||
74 | /* Prevent VMA merging */ | ||
75 | static void syscall_vma_close(struct vm_area_struct *vma) | ||
76 | { | ||
77 | } | ||
78 | |||
79 | static struct vm_operations_struct syscall_vm_ops = { | ||
80 | .nopage = syscall_vma_nopage, | ||
81 | .close = syscall_vma_close, | ||
82 | }; | ||
83 | |||
84 | /* Setup a VMA at program startup for the vsyscall page */ | ||
85 | int arch_setup_additional_pages(struct linux_binprm *bprm, | ||
86 | int executable_stack) | ||
87 | { | ||
88 | struct vm_area_struct *vma; | ||
89 | struct mm_struct *mm = current->mm; | ||
90 | unsigned long addr; | ||
91 | int ret; | ||
92 | |||
93 | down_write(&mm->mmap_sem); | ||
94 | addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); | ||
95 | if (IS_ERR_VALUE(addr)) { | ||
96 | ret = addr; | ||
97 | goto up_fail; | ||
98 | } | ||
99 | |||
100 | vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); | ||
101 | if (!vma) { | ||
102 | ret = -ENOMEM; | ||
103 | goto up_fail; | ||
104 | } | ||
105 | |||
106 | vma->vm_start = addr; | ||
107 | vma->vm_end = addr + PAGE_SIZE; | ||
108 | /* MAYWRITE to allow gdb to COW and set breakpoints */ | ||
109 | vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; | ||
110 | vma->vm_flags |= mm->def_flags; | ||
111 | vma->vm_page_prot = protection_map[vma->vm_flags & 7]; | ||
112 | vma->vm_ops = &syscall_vm_ops; | ||
113 | vma->vm_mm = mm; | ||
114 | |||
115 | ret = insert_vm_struct(mm, vma); | ||
116 | if (unlikely(ret)) { | ||
117 | kmem_cache_free(vm_area_cachep, vma); | ||
118 | goto up_fail; | ||
119 | } | ||
120 | |||
121 | current->mm->context.vdso = (void *)addr; | ||
122 | |||
123 | mm->total_vm++; | ||
124 | up_fail: | ||
125 | up_write(&mm->mmap_sem); | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | const char *arch_vma_name(struct vm_area_struct *vma) | ||
130 | { | ||
131 | if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) | ||
132 | return "[vdso]"; | ||
133 | |||
134 | return NULL; | ||
135 | } | ||
136 | |||
137 | struct vm_area_struct *get_gate_vma(struct task_struct *task) | ||
138 | { | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | int in_gate_area(struct task_struct *task, unsigned long address) | ||
143 | { | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | int in_gate_area_no_task(unsigned long address) | ||
148 | { | ||
149 | return 0; | ||
150 | } | ||
diff --git a/arch/sh/kernel/vsyscall/vsyscall.lds.S b/arch/sh/kernel/vsyscall/vsyscall.lds.S new file mode 100644 index 000000000000..b13c3d439fee --- /dev/null +++ b/arch/sh/kernel/vsyscall/vsyscall.lds.S | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Linker script for vsyscall DSO. The vsyscall page is an ELF shared | ||
3 | * object prelinked to its virtual address, and with only one read-only | ||
4 | * segment (that fits in one page). This script controls its layout. | ||
5 | */ | ||
6 | #include <asm/asm-offsets.h> | ||
7 | |||
8 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
9 | OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux") | ||
10 | #else | ||
11 | OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux") | ||
12 | #endif | ||
13 | OUTPUT_ARCH(sh) | ||
14 | |||
15 | /* The ELF entry point can be used to set the AT_SYSINFO value. */ | ||
16 | ENTRY(__kernel_vsyscall); | ||
17 | |||
18 | SECTIONS | ||
19 | { | ||
20 | . = SIZEOF_HEADERS; | ||
21 | |||
22 | .hash : { *(.hash) } :text | ||
23 | .gnu.hash : { *(.gnu.hash) } | ||
24 | .dynsym : { *(.dynsym) } | ||
25 | .dynstr : { *(.dynstr) } | ||
26 | .gnu.version : { *(.gnu.version) } | ||
27 | .gnu.version_d : { *(.gnu.version_d) } | ||
28 | .gnu.version_r : { *(.gnu.version_r) } | ||
29 | |||
30 | /* This linker script is used both with -r and with -shared. | ||
31 | For the layouts to match, we need to skip more than enough | ||
32 | space for the dynamic symbol table et al. If this amount | ||
33 | is insufficient, ld -shared will barf. Just increase it here. */ | ||
34 | . = 0x400; | ||
35 | |||
36 | .text : { *(.text) } :text =0x90909090 | ||
37 | .note : { *(.note.*) } :text :note | ||
38 | .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr | ||
39 | .eh_frame : { KEEP (*(.eh_frame)) } :text | ||
40 | .dynamic : { *(.dynamic) } :text :dynamic | ||
41 | .useless : { | ||
42 | *(.got.plt) *(.got) | ||
43 | *(.data .data.* .gnu.linkonce.d.*) | ||
44 | *(.dynbss) | ||
45 | *(.bss .bss.* .gnu.linkonce.b.*) | ||
46 | } :text | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * We must supply the ELF program headers explicitly to get just one | ||
51 | * PT_LOAD segment, and set the flags explicitly to make segments read-only. | ||
52 | */ | ||
53 | PHDRS | ||
54 | { | ||
55 | text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ | ||
56 | dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ | ||
57 | note PT_NOTE FLAGS(4); /* PF_R */ | ||
58 | eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * This controls what symbols we export from the DSO. | ||
63 | */ | ||
64 | VERSION | ||
65 | { | ||
66 | LINUX_2.6 { | ||
67 | global: | ||
68 | __kernel_vsyscall; | ||
69 | __kernel_sigreturn; | ||
70 | __kernel_rt_sigreturn; | ||
71 | |||
72 | local: *; | ||
73 | }; | ||
74 | } | ||
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index b445d02075e8..9dd606464d23 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig | |||
@@ -223,6 +223,19 @@ config 32BIT | |||
223 | 32-bits through the SH-4A PMB. If this is not set, legacy | 223 | 32-bits through the SH-4A PMB. If this is not set, legacy |
224 | 29-bit physical addressing will be used. | 224 | 29-bit physical addressing will be used. |
225 | 225 | ||
226 | config VSYSCALL | ||
227 | bool "Support vsyscall page" | ||
228 | depends on MMU | ||
229 | default y | ||
230 | help | ||
231 | This will enable support for the kernel mapping a vDSO page | ||
232 | in process space, and subsequently handing down the entry point | ||
233 | to the libc through the ELF auxiliary vector. | ||
234 | |||
235 | From the kernel side this is used for the signal trampoline. | ||
236 | For systems with an MMU that can afford to give up a page, | ||
237 | (the default value) say Y. | ||
238 | |||
226 | choice | 239 | choice |
227 | prompt "HugeTLB page size" | 240 | prompt "HugeTLB page size" |
228 | depends on HUGETLB_PAGE && CPU_SH4 && MMU | 241 | depends on HUGETLB_PAGE && CPU_SH4 && MMU |
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index ad182b31d846..7154d1ce9785 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c | |||
@@ -286,6 +286,9 @@ void __init mem_init(void) | |||
286 | initsize >> 10); | 286 | initsize >> 10); |
287 | 287 | ||
288 | p3_cache_init(); | 288 | p3_cache_init(); |
289 | |||
290 | /* Initialize the vDSO */ | ||
291 | vsyscall_init(); | ||
289 | } | 292 | } |
290 | 293 | ||
291 | void free_initmem(void) | 294 | void free_initmem(void) |
diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlb-flush.c index fd7e42bcaa40..73ec7f6084fa 100644 --- a/arch/sh/mm/tlb-flush.c +++ b/arch/sh/mm/tlb-flush.c | |||
@@ -14,12 +14,12 @@ | |||
14 | 14 | ||
15 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | 15 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) |
16 | { | 16 | { |
17 | if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) { | 17 | if (vma->vm_mm && vma->vm_mm->context.id != NO_CONTEXT) { |
18 | unsigned long flags; | 18 | unsigned long flags; |
19 | unsigned long asid; | 19 | unsigned long asid; |
20 | unsigned long saved_asid = MMU_NO_ASID; | 20 | unsigned long saved_asid = MMU_NO_ASID; |
21 | 21 | ||
22 | asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK; | 22 | asid = vma->vm_mm->context.id & MMU_CONTEXT_ASID_MASK; |
23 | page &= PAGE_MASK; | 23 | page &= PAGE_MASK; |
24 | 24 | ||
25 | local_irq_save(flags); | 25 | local_irq_save(flags); |
@@ -39,20 +39,21 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | |||
39 | { | 39 | { |
40 | struct mm_struct *mm = vma->vm_mm; | 40 | struct mm_struct *mm = vma->vm_mm; |
41 | 41 | ||
42 | if (mm->context != NO_CONTEXT) { | 42 | if (mm->context.id != NO_CONTEXT) { |
43 | unsigned long flags; | 43 | unsigned long flags; |
44 | int size; | 44 | int size; |
45 | 45 | ||
46 | local_irq_save(flags); | 46 | local_irq_save(flags); |
47 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; | 47 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; |
48 | if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ | 48 | if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ |
49 | mm->context = NO_CONTEXT; | 49 | mm->context.id = NO_CONTEXT; |
50 | if (mm == current->mm) | 50 | if (mm == current->mm) |
51 | activate_context(mm); | 51 | activate_context(mm); |
52 | } else { | 52 | } else { |
53 | unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK; | 53 | unsigned long asid; |
54 | unsigned long saved_asid = MMU_NO_ASID; | 54 | unsigned long saved_asid = MMU_NO_ASID; |
55 | 55 | ||
56 | asid = mm->context.id & MMU_CONTEXT_ASID_MASK; | ||
56 | start &= PAGE_MASK; | 57 | start &= PAGE_MASK; |
57 | end += (PAGE_SIZE - 1); | 58 | end += (PAGE_SIZE - 1); |
58 | end &= PAGE_MASK; | 59 | end &= PAGE_MASK; |
@@ -81,9 +82,10 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) | |||
81 | if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ | 82 | if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ |
82 | flush_tlb_all(); | 83 | flush_tlb_all(); |
83 | } else { | 84 | } else { |
84 | unsigned long asid = init_mm.context&MMU_CONTEXT_ASID_MASK; | 85 | unsigned long asid; |
85 | unsigned long saved_asid = get_asid(); | 86 | unsigned long saved_asid = get_asid(); |
86 | 87 | ||
88 | asid = init_mm.context.id & MMU_CONTEXT_ASID_MASK; | ||
87 | start &= PAGE_MASK; | 89 | start &= PAGE_MASK; |
88 | end += (PAGE_SIZE - 1); | 90 | end += (PAGE_SIZE - 1); |
89 | end &= PAGE_MASK; | 91 | end &= PAGE_MASK; |
@@ -101,11 +103,11 @@ void flush_tlb_mm(struct mm_struct *mm) | |||
101 | { | 103 | { |
102 | /* Invalidate all TLB of this process. */ | 104 | /* Invalidate all TLB of this process. */ |
103 | /* Instead of invalidating each TLB, we get new MMU context. */ | 105 | /* Instead of invalidating each TLB, we get new MMU context. */ |
104 | if (mm->context != NO_CONTEXT) { | 106 | if (mm->context.id != NO_CONTEXT) { |
105 | unsigned long flags; | 107 | unsigned long flags; |
106 | 108 | ||
107 | local_irq_save(flags); | 109 | local_irq_save(flags); |
108 | mm->context = NO_CONTEXT; | 110 | mm->context.id = NO_CONTEXT; |
109 | if (mm == current->mm) | 111 | if (mm == current->mm) |
110 | activate_context(mm); | 112 | activate_context(mm); |
111 | local_irq_restore(flags); | 113 | local_irq_restore(flags); |
diff --git a/include/asm-sh/auxvec.h b/include/asm-sh/auxvec.h index fc21e4db5881..1b6916e63e90 100644 --- a/include/asm-sh/auxvec.h +++ b/include/asm-sh/auxvec.h | |||
@@ -1,4 +1,18 @@ | |||
1 | #ifndef __ASM_SH_AUXVEC_H | 1 | #ifndef __ASM_SH_AUXVEC_H |
2 | #define __ASM_SH_AUXVEC_H | 2 | #define __ASM_SH_AUXVEC_H |
3 | 3 | ||
4 | /* | ||
5 | * Architecture-neutral AT_ values in 0-17, leave some room | ||
6 | * for more of them. | ||
7 | */ | ||
8 | |||
9 | #ifdef CONFIG_VSYSCALL | ||
10 | /* | ||
11 | * Only define this in the vsyscall case, the entry point to | ||
12 | * the vsyscall page gets placed here. The kernel will attempt | ||
13 | * to build a gate VMA we don't care about otherwise.. | ||
14 | */ | ||
15 | #define AT_SYSINFO_EHDR 33 | ||
16 | #endif | ||
17 | |||
4 | #endif /* __ASM_SH_AUXVEC_H */ | 18 | #endif /* __ASM_SH_AUXVEC_H */ |
diff --git a/include/asm-sh/elf.h b/include/asm-sh/elf.h index cc8e5e767345..3a07ab40ac4d 100644 --- a/include/asm-sh/elf.h +++ b/include/asm-sh/elf.h | |||
@@ -121,4 +121,24 @@ extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); | |||
121 | #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) | 121 | #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) |
122 | #endif | 122 | #endif |
123 | 123 | ||
124 | #ifdef CONFIG_VSYSCALL | ||
125 | /* vDSO has arch_setup_additional_pages */ | ||
126 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES | ||
127 | struct linux_binprm; | ||
128 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, | ||
129 | int executable_stack); | ||
130 | |||
131 | extern unsigned int vdso_enabled; | ||
132 | extern void __kernel_vsyscall; | ||
133 | |||
134 | #define VDSO_BASE ((unsigned long)current->mm->context.vdso) | ||
135 | #define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x)) | ||
136 | |||
137 | #define ARCH_DLINFO \ | ||
138 | do { \ | ||
139 | if (vdso_enabled) \ | ||
140 | NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \ | ||
141 | } while (0) | ||
142 | #endif /* CONFIG_VSYSCALL */ | ||
143 | |||
124 | #endif /* __ASM_SH_ELF_H */ | 144 | #endif /* __ASM_SH_ELF_H */ |
diff --git a/include/asm-sh/mmu.h b/include/asm-sh/mmu.h index 6383dc84501e..cf47df79bb94 100644 --- a/include/asm-sh/mmu.h +++ b/include/asm-sh/mmu.h | |||
@@ -11,7 +11,12 @@ typedef struct { | |||
11 | #else | 11 | #else |
12 | 12 | ||
13 | /* Default "unsigned long" context */ | 13 | /* Default "unsigned long" context */ |
14 | typedef unsigned long mm_context_t; | 14 | typedef unsigned long mm_context_id_t; |
15 | |||
16 | typedef struct { | ||
17 | mm_context_id_t id; | ||
18 | void *vdso; | ||
19 | } mm_context_t; | ||
15 | 20 | ||
16 | #endif /* CONFIG_MMU */ | 21 | #endif /* CONFIG_MMU */ |
17 | 22 | ||
diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h index 87678ba8d6b6..c7088efe579a 100644 --- a/include/asm-sh/mmu_context.h +++ b/include/asm-sh/mmu_context.h | |||
@@ -49,7 +49,7 @@ get_mmu_context(struct mm_struct *mm) | |||
49 | unsigned long mc = mmu_context_cache; | 49 | unsigned long mc = mmu_context_cache; |
50 | 50 | ||
51 | /* Check if we have old version of context. */ | 51 | /* Check if we have old version of context. */ |
52 | if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0) | 52 | if (((mm->context.id ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0) |
53 | /* It's up to date, do nothing */ | 53 | /* It's up to date, do nothing */ |
54 | return; | 54 | return; |
55 | 55 | ||
@@ -68,7 +68,7 @@ get_mmu_context(struct mm_struct *mm) | |||
68 | if (!mc) | 68 | if (!mc) |
69 | mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION; | 69 | mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION; |
70 | } | 70 | } |
71 | mm->context = mc; | 71 | mm->context.id = mc; |
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
@@ -78,7 +78,7 @@ get_mmu_context(struct mm_struct *mm) | |||
78 | static __inline__ int init_new_context(struct task_struct *tsk, | 78 | static __inline__ int init_new_context(struct task_struct *tsk, |
79 | struct mm_struct *mm) | 79 | struct mm_struct *mm) |
80 | { | 80 | { |
81 | mm->context = NO_CONTEXT; | 81 | mm->context.id = NO_CONTEXT; |
82 | 82 | ||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
@@ -123,7 +123,7 @@ static __inline__ unsigned long get_asid(void) | |||
123 | static __inline__ void activate_context(struct mm_struct *mm) | 123 | static __inline__ void activate_context(struct mm_struct *mm) |
124 | { | 124 | { |
125 | get_mmu_context(mm); | 125 | get_mmu_context(mm); |
126 | set_asid(mm->context & MMU_CONTEXT_ASID_MASK); | 126 | set_asid(mm->context.id & MMU_CONTEXT_ASID_MASK); |
127 | } | 127 | } |
128 | 128 | ||
129 | /* MMU_TTB can be used for optimizing the fault handling. | 129 | /* MMU_TTB can be used for optimizing the fault handling. |
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index acf6977b4042..3d8dae31a6f6 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h | |||
@@ -117,5 +117,10 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
117 | #include <asm-generic/memory_model.h> | 117 | #include <asm-generic/memory_model.h> |
118 | #include <asm-generic/page.h> | 118 | #include <asm-generic/page.h> |
119 | 119 | ||
120 | /* vDSO support */ | ||
121 | #ifdef CONFIG_VSYSCALL | ||
122 | #define __HAVE_ARCH_GATE_AREA | ||
123 | #endif | ||
124 | |||
120 | #endif /* __KERNEL__ */ | 125 | #endif /* __KERNEL__ */ |
121 | #endif /* __ASM_SH_PAGE_H */ | 126 | #endif /* __ASM_SH_PAGE_H */ |
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index b7cba4e91a72..474773853cd1 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h | |||
@@ -276,5 +276,11 @@ static inline void prefetch(void *x) | |||
276 | #define prefetchw(x) prefetch(x) | 276 | #define prefetchw(x) prefetch(x) |
277 | #endif | 277 | #endif |
278 | 278 | ||
279 | #ifdef CONFIG_VSYSCALL | ||
280 | extern int vsyscall_init(void); | ||
281 | #else | ||
282 | #define vsyscall_init() do { } while (0) | ||
283 | #endif | ||
284 | |||
279 | #endif /* __KERNEL__ */ | 285 | #endif /* __KERNEL__ */ |
280 | #endif /* __ASM_SH_PROCESSOR_H */ | 286 | #endif /* __ASM_SH_PROCESSOR_H */ |