aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-10-14 01:41:42 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-22 22:31:01 -0400
commit7147e215480323bb2617fcebf585c447188ff760 (patch)
treefb5d92e4f9e2f4d5d5c8e4449c4ef43e05275826 /arch/sh
parentddffeb8c4d0331609ef2581d84de4d763607bd37 (diff)
sh: switch to generic kernel_thread()/kernel_execve()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/Kconfig2
-rw-r--r--arch/sh/include/asm/processor_32.h5
-rw-r--r--arch/sh/include/asm/processor_64.h5
-rw-r--r--arch/sh/kernel/Makefile3
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S19
-rw-r--r--arch/sh/kernel/entry-common.S13
-rw-r--r--arch/sh/kernel/process_32.c64
-rw-r--r--arch/sh/kernel/process_64.c60
-rw-r--r--arch/sh/kernel/sys_sh32.c24
-rw-r--r--arch/sh/kernel/sys_sh64.c50
10 files changed, 71 insertions, 174 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index babc2b826c5c..8451317eed58 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -40,6 +40,8 @@ config SUPERH
40 select GENERIC_STRNLEN_USER 40 select GENERIC_STRNLEN_USER
41 select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER 41 select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
42 select MODULES_USE_ELF_RELA 42 select MODULES_USE_ELF_RELA
43 select GENERIC_KERNEL_THREAD
44 select GENERIC_KERNEL_EXECVE
43 help 45 help
44 The SuperH is a RISC processor targeted for use in embedded systems 46 The SuperH is a RISC processor targeted for use in embedded systems
45 and consumer electronics; it was also used in the Sega Dreamcast 47 and consumer electronics; it was also used in the Sega Dreamcast
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index b6311fd2d066..b1320d55ca30 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -126,11 +126,6 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned lo
126/* Free all resources held by a thread. */ 126/* Free all resources held by a thread. */
127extern void release_thread(struct task_struct *); 127extern void release_thread(struct task_struct *);
128 128
129/*
130 * create a kernel thread without removing it from tasklists
131 */
132extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
133
134/* Copy and release all segment info associated with a VM */ 129/* Copy and release all segment info associated with a VM */
135#define copy_segments(p, mm) do { } while(0) 130#define copy_segments(p, mm) do { } while(0)
136#define release_segments(mm) do { } while(0) 131#define release_segments(mm) do { } while(0)
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h
index cd6029fb2c01..1ee8946f0952 100644
--- a/arch/sh/include/asm/processor_64.h
+++ b/arch/sh/include/asm/processor_64.h
@@ -159,11 +159,6 @@ struct mm_struct;
159 159
160/* Free all resources held by a thread. */ 160/* Free all resources held by a thread. */
161extern void release_thread(struct task_struct *); 161extern void release_thread(struct task_struct *);
162/*
163 * create a kernel thread without removing it from tasklists
164 */
165extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
166
167 162
168/* Copy and release all segment info associated with a VM */ 163/* Copy and release all segment info associated with a VM */
169#define copy_segments(p, mm) do { } while (0) 164#define copy_segments(p, mm) do { } while (0)
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 88571ff8eeec..f259b37874e9 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -16,7 +16,7 @@ obj-y := debugtraps.o dma-nommu.o dumpstack.o \
16 machvec.o nmi_debug.o process.o \ 16 machvec.o nmi_debug.o process.o \
17 process_$(BITS).o ptrace.o ptrace_$(BITS).o \ 17 process_$(BITS).o ptrace.o ptrace_$(BITS).o \
18 reboot.o return_address.o \ 18 reboot.o return_address.o \
19 setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ 19 setup.o signal_$(BITS).o sys_sh.o \
20 syscalls_$(BITS).o time.o topology.o traps.o \ 20 syscalls_$(BITS).o time.o topology.o traps.o \
21 traps_$(BITS).o unwinder.o 21 traps_$(BITS).o unwinder.o
22 22
@@ -25,6 +25,7 @@ obj-y += iomap.o
25obj-$(CONFIG_HAS_IOPORT) += ioport.o 25obj-$(CONFIG_HAS_IOPORT) += ioport.o
26endif 26endif
27 27
28obj-$(CONFIG_SUPERH32) += sys_sh32.o
28obj-y += cpu/ 29obj-y += cpu/
29obj-$(CONFIG_VSYSCALL) += vsyscall/ 30obj-$(CONFIG_VSYSCALL) += vsyscall/
30obj-$(CONFIG_SMP) += smp.o 31obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index 7e605b95592a..0c8d0377d40b 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -1228,6 +1228,25 @@ ret_from_fork:
1228 pta ret_from_syscall, tr0 1228 pta ret_from_syscall, tr0
1229 blink tr0, ZERO 1229 blink tr0, ZERO
1230 1230
1231.global ret_from_kernel_thread
1232ret_from_kernel_thread:
1233
1234 movi schedule_tail,r5
1235 ori r5, 1, r5
1236 ptabs r5, tr0
1237 blink tr0, LINK
1238
1239 ld.q SP, FRAME_R(2), r2
1240 ld.q SP, FRAME_R(3), r3
1241 ptabs r3, tr0
1242 blink tr0, LINK
1243
1244 ld.q SP, FRAME_S(FSPC), r2
1245 addi r2, 4, r2 /* Move PC, being pre-execution event */
1246 st.q SP, FRAME_S(FSPC), r2
1247 pta ret_from_syscall, tr0
1248 blink tr0, ZERO
1249
1231syscall_allowed: 1250syscall_allowed:
1232 /* Use LINK to deflect the exit point, default is syscall_ret */ 1251 /* Use LINK to deflect the exit point, default is syscall_ret */
1233 pta syscall_ret, tr0 1252 pta syscall_ret, tr0
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index b96489d8b27d..9b6e4beeb296 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -297,6 +297,19 @@ ret_from_fork:
297 mov r0, r4 297 mov r0, r4
298 bra syscall_exit 298 bra syscall_exit
299 nop 299 nop
300
301 .align 2
302 .globl ret_from_kernel_thread
303ret_from_kernel_thread:
304 mov.l 1f, r8
305 jsr @r8
306 mov r0, r4
307 mov.l @(OFF_R5,r15), r5 ! fn
308 jsr @r5
309 mov.l @(OFF_R4,r15), r4 ! arg
310 bra syscall_exit
311 nop
312
300 .align 2 313 .align 2
3011: .long schedule_tail 3141: .long schedule_tail
302 315
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index ba7345f37bc9..b55070b9a634 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -68,38 +68,6 @@ void show_regs(struct pt_regs * regs)
68 show_code(regs); 68 show_code(regs);
69} 69}
70 70
71/*
72 * Create a kernel thread
73 */
74__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
75{
76 do_exit(fn(arg));
77}
78
79/* Don't use this in BL=1(cli). Or else, CPU resets! */
80int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
81{
82 struct pt_regs regs;
83 int pid;
84
85 memset(&regs, 0, sizeof(regs));
86 regs.regs[4] = (unsigned long)arg;
87 regs.regs[5] = (unsigned long)fn;
88
89 regs.pc = (unsigned long)kernel_thread_helper;
90 regs.sr = SR_MD;
91#if defined(CONFIG_SH_FPU)
92 regs.sr |= SR_FD;
93#endif
94
95 /* Ok, create the new process.. */
96 pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
97 &regs, 0, NULL, NULL);
98
99 return pid;
100}
101EXPORT_SYMBOL(kernel_thread);
102
103void start_thread(struct pt_regs *regs, unsigned long new_pc, 71void start_thread(struct pt_regs *regs, unsigned long new_pc,
104 unsigned long new_sp) 72 unsigned long new_sp)
105{ 73{
@@ -157,9 +125,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
157EXPORT_SYMBOL(dump_fpu); 125EXPORT_SYMBOL(dump_fpu);
158 126
159asmlinkage void ret_from_fork(void); 127asmlinkage void ret_from_fork(void);
128asmlinkage void ret_from_kernel_thread(void);
160 129
161int copy_thread(unsigned long clone_flags, unsigned long usp, 130int copy_thread(unsigned long clone_flags, unsigned long usp,
162 unsigned long unused, 131 unsigned long arg,
163 struct task_struct *p, struct pt_regs *regs) 132 struct task_struct *p, struct pt_regs *regs)
164{ 133{
165 struct thread_info *ti = task_thread_info(p); 134 struct thread_info *ti = task_thread_info(p);
@@ -177,29 +146,34 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
177 } 146 }
178#endif 147#endif
179 148
180 childregs = task_pt_regs(p); 149 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
181 *childregs = *regs;
182 150
183 if (user_mode(regs)) { 151 childregs = task_pt_regs(p);
184 childregs->regs[15] = usp; 152 p->thread.sp = (unsigned long) childregs;
185 ti->addr_limit = USER_DS; 153 if (unlikely(p->flags & PF_KTHREAD)) {
186 } else { 154 memset(childregs, 0, sizeof(struct pt_regs));
187 childregs->regs[15] = (unsigned long)childregs; 155 p->thread.pc = (unsigned long) ret_from_kernel_thread;
156 childregs->regs[4] = arg;
157 childregs->regs[5] = usp;
158 childregs->sr = SR_MD;
159#if defined(CONFIG_SH_FPU)
160 childregs->sr |= SR_FD;
161#endif
188 ti->addr_limit = KERNEL_DS; 162 ti->addr_limit = KERNEL_DS;
189 ti->status &= ~TS_USEDFPU; 163 ti->status &= ~TS_USEDFPU;
190 p->fpu_counter = 0; 164 p->fpu_counter = 0;
165 return 0;
191 } 166 }
167 *childregs = *regs;
168
169 childregs->regs[15] = usp;
170 ti->addr_limit = USER_DS;
192 171
193 if (clone_flags & CLONE_SETTLS) 172 if (clone_flags & CLONE_SETTLS)
194 childregs->gbr = childregs->regs[0]; 173 childregs->gbr = childregs->regs[0];
195 174
196 childregs->regs[0] = 0; /* Set return value for child */ 175 childregs->regs[0] = 0; /* Set return value for child */
197
198 p->thread.sp = (unsigned long) childregs;
199 p->thread.pc = (unsigned long) ret_from_fork; 176 p->thread.pc = (unsigned long) ret_from_fork;
200
201 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
202
203 return 0; 177 return 0;
204} 178}
205 179
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index 98a709f0c3c4..fd338b030fd9 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -285,39 +285,6 @@ void show_regs(struct pt_regs *regs)
285} 285}
286 286
287/* 287/*
288 * Create a kernel thread
289 */
290__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
291{
292 do_exit(fn(arg));
293}
294
295/*
296 * This is the mechanism for creating a new kernel thread.
297 *
298 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
299 * who haven't done an "execve()") should use this: it will work within
300 * a system call from a "real" process, but the process memory space will
301 * not be freed until both the parent and the child have exited.
302 */
303int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
304{
305 struct pt_regs regs;
306
307 memset(&regs, 0, sizeof(regs));
308 regs.regs[2] = (unsigned long)arg;
309 regs.regs[3] = (unsigned long)fn;
310
311 regs.pc = (unsigned long)kernel_thread_helper;
312 regs.sr = (1 << 30);
313
314 /* Ok, create the new process.. */
315 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
316 &regs, 0, NULL, NULL);
317}
318EXPORT_SYMBOL(kernel_thread);
319
320/*
321 * Free current thread data structures etc.. 288 * Free current thread data structures etc..
322 */ 289 */
323void exit_thread(void) 290void exit_thread(void)
@@ -401,15 +368,17 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
401EXPORT_SYMBOL(dump_fpu); 368EXPORT_SYMBOL(dump_fpu);
402 369
403asmlinkage void ret_from_fork(void); 370asmlinkage void ret_from_fork(void);
371asmlinkage void ret_from_kernel_thread(void);
404 372
405int copy_thread(unsigned long clone_flags, unsigned long usp, 373int copy_thread(unsigned long clone_flags, unsigned long usp,
406 unsigned long unused, 374 unsigned long arg,
407 struct task_struct *p, struct pt_regs *regs) 375 struct task_struct *p, struct pt_regs *regs)
408{ 376{
409 struct pt_regs *childregs; 377 struct pt_regs *childregs;
410 378
411#ifdef CONFIG_SH_FPU 379#ifdef CONFIG_SH_FPU
412 if(last_task_used_math == current) { 380 /* can't happen for a kernel thread */
381 if (last_task_used_math == current) {
413 enable_fpu(); 382 enable_fpu();
414 save_fpu(current); 383 save_fpu(current);
415 disable_fpu(); 384 disable_fpu();
@@ -419,7 +388,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
419#endif 388#endif
420 /* Copy from sh version */ 389 /* Copy from sh version */
421 childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1; 390 childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
391 p->thread.sp = (unsigned long) childregs;
422 392
393 if (unlikely(p->flags & PF_KTHREAD)) {
394 memset(childregs, 0, sizeof(struct pt_regs));
395 childregs->regs[2] = (unsigned long)arg;
396 childregs->regs[3] = (unsigned long)fn;
397 childregs->sr = (1 << 30); /* not user_mode */
398 childregs->sr |= SR_FD; /* Invalidate FPU flag */
399 p->thread.pc = (unsigned long) ret_from_kernel_thread;
400 return 0;
401 }
423 *childregs = *regs; 402 *childregs = *regs;
424 403
425 /* 404 /*
@@ -428,19 +407,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
428 * 32-bit wide and context switch must take care 407 * 32-bit wide and context switch must take care
429 * of NEFF sign extension. 408 * of NEFF sign extension.
430 */ 409 */
431 if (user_mode(regs)) { 410 childregs->regs[15] = neff_sign_extend(usp);
432 childregs->regs[15] = neff_sign_extend(usp); 411 p->thread.uregs = childregs;
433 p->thread.uregs = childregs;
434 } else {
435 childregs->regs[15] =
436 neff_sign_extend((unsigned long)task_stack_page(p) +
437 THREAD_SIZE);
438 }
439 412
440 childregs->regs[9] = 0; /* Set return value for child */ 413 childregs->regs[9] = 0; /* Set return value for child */
441 childregs->sr |= SR_FD; /* Invalidate FPU flag */ 414 childregs->sr |= SR_FD; /* Invalidate FPU flag */
442 415
443 p->thread.sp = (unsigned long) childregs;
444 p->thread.pc = (unsigned long) ret_from_fork; 416 p->thread.pc = (unsigned long) ret_from_fork;
445 417
446 return 0; 418 return 0;
diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c
index f56b6fe5c5d0..497bab3a0401 100644
--- a/arch/sh/kernel/sys_sh32.c
+++ b/arch/sh/kernel/sys_sh32.c
@@ -60,27 +60,3 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
60 (u64)len0 << 32 | len1, advice); 60 (u64)len0 << 32 | len1, advice);
61#endif 61#endif
62} 62}
63
64#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
65#define SYSCALL_ARG3 "trapa #0x23"
66#else
67#define SYSCALL_ARG3 "trapa #0x13"
68#endif
69
70/*
71 * Do a system call from kernel instead of calling sys_execve so we
72 * end up with proper pt_regs.
73 */
74int kernel_execve(const char *filename,
75 const char *const argv[],
76 const char *const envp[])
77{
78 register long __sc0 __asm__ ("r3") = __NR_execve;
79 register long __sc4 __asm__ ("r4") = (long) filename;
80 register long __sc5 __asm__ ("r5") = (long) argv;
81 register long __sc6 __asm__ ("r6") = (long) envp;
82 __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)
83 : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
84 : "memory");
85 return __sc0;
86}
diff --git a/arch/sh/kernel/sys_sh64.c b/arch/sh/kernel/sys_sh64.c
deleted file mode 100644
index c5a38c4bf410..000000000000
--- a/arch/sh/kernel/sys_sh64.c
+++ /dev/null
@@ -1,50 +0,0 @@
1/*
2 * arch/sh/kernel/sys_sh64.c
3 *
4 * Copyright (C) 2000, 2001 Paolo Alberelli
5 *
6 * This file contains various random system calls that
7 * have a non-standard calling sequence on the Linux/SH5
8 * platform.
9 *
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file "COPYING" in the main directory of this archive
12 * for more details.
13 */
14#include <linux/errno.h>
15#include <linux/rwsem.h>
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <linux/fs.h>
19#include <linux/smp.h>
20#include <linux/sem.h>
21#include <linux/msg.h>
22#include <linux/shm.h>
23#include <linux/stat.h>
24#include <linux/mman.h>
25#include <linux/file.h>
26#include <linux/syscalls.h>
27#include <linux/ipc.h>
28#include <asm/uaccess.h>
29#include <asm/ptrace.h>
30#include <asm/unistd.h>
31
32/*
33 * Do a system call from kernel instead of calling sys_execve so we
34 * end up with proper pt_regs.
35 */
36int kernel_execve(const char *filename,
37 const char *const argv[],
38 const char *const envp[])
39{
40 register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve);
41 register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename;
42 register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv;
43 register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp;
44 __asm__ __volatile__ ("trapa %1 !\t\t\t execve(%2,%3,%4)"
45 : "=r" (__sc0)
46 : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );
47 __asm__ __volatile__ ("!dummy %0 %1 %2 %3"
48 : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory");
49 return __sc0;
50}