aboutsummaryrefslogtreecommitdiffstats
path: root/arch/frv/kernel
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-09-18 22:18:51 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-01 00:53:10 -0400
commit02ce496f152df87be081a64796498942c433a2fd (patch)
tree0e6bdae8a5c9b1538f45c198cae7715957b997ba /arch/frv/kernel
parentd878d6dacee2c862f02da20f7fa3e2c0e8820e71 (diff)
frv: split ret_from_fork, simplify kernel_thread() a lot
Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/frv/kernel')
-rw-r--r--arch/frv/kernel/Makefile2
-rw-r--r--arch/frv/kernel/entry.S8
-rw-r--r--arch/frv/kernel/frv_ksyms.c1
-rw-r--r--arch/frv/kernel/kernel_thread.S77
-rw-r--r--arch/frv/kernel/process.c44
5 files changed, 32 insertions, 100 deletions
diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile
index ad4087b6996..7b10bc19106 100644
--- a/arch/frv/kernel/Makefile
+++ b/arch/frv/kernel/Makefile
@@ -7,7 +7,7 @@ heads-$(CONFIG_MMU) := head-mmu-fr451.o
7 7
8extra-y:= head.o vmlinux.lds 8extra-y:= head.o vmlinux.lds
9 9
10obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ 10obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o \
11 kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \ 11 kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \
12 sys_frv.o time.o setup.o frv_ksyms.o \ 12 sys_frv.o time.o setup.o frv_ksyms.o \
13 debug-stub.o irq.o sleep.o uaccess.o 13 debug-stub.o irq.o sleep.o uaccess.o
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 7d5e000fd32..7a886130ca1 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -863,6 +863,14 @@ ret_from_fork:
863 setlos.p #0,gr8 863 setlos.p #0,gr8
864 bra __syscall_exit 864 bra __syscall_exit
865 865
866 .globl ret_from_kernel_thread
867ret_from_kernel_thread:
868 lddi.p @(gr28,#REG_GR(8)),gr20
869 call schedule_tail
870 or.p gr20,gr20,gr8
871 calll @(gr21,gr0)
872 bra sys_exit
873
866################################################################################################### 874###################################################################################################
867# 875#
868# Return to user mode is not as complex as all this looks, 876# Return to user mode is not as complex as all this looks,
diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c
index a89803b58b9..86c516d96dc 100644
--- a/arch/frv/kernel/frv_ksyms.c
+++ b/arch/frv/kernel/frv_ksyms.c
@@ -30,7 +30,6 @@ EXPORT_SYMBOL(ip_fast_csum);
30EXPORT_SYMBOL(local_irq_count); 30EXPORT_SYMBOL(local_irq_count);
31EXPORT_SYMBOL(local_bh_count); 31EXPORT_SYMBOL(local_bh_count);
32#endif 32#endif
33EXPORT_SYMBOL(kernel_thread);
34 33
35EXPORT_SYMBOL(__res_bus_clock_speed_HZ); 34EXPORT_SYMBOL(__res_bus_clock_speed_HZ);
36EXPORT_SYMBOL(__page_offset); 35EXPORT_SYMBOL(__page_offset);
diff --git a/arch/frv/kernel/kernel_thread.S b/arch/frv/kernel/kernel_thread.S
deleted file mode 100644
index f0e52943f92..00000000000
--- a/arch/frv/kernel/kernel_thread.S
+++ /dev/null
@@ -1,77 +0,0 @@
1/* kernel_thread.S: kernel thread creation
2 *
3 * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/linkage.h>
13#include <linux/kern_levels.h>
14#include <asm/unistd.h>
15
16#define CLONE_VM 0x00000100 /* set if VM shared between processes */
17
18 .section .rodata
19kernel_thread_emsg:
20 .asciz KERN_ERR "failed to create kernel thread: error=%d\n"
21
22 .text
23 .balign 4
24
25###############################################################################
26#
27# Create a kernel thread
28#
29# int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
30#
31###############################################################################
32 .globl kernel_thread
33 .type kernel_thread,@function
34kernel_thread:
35 or.p gr8,gr0,gr4
36 or gr9,gr0,gr5
37
38 # start by forking the current process, but with shared VM
39 setlos.p #__NR_clone,gr7 ; syscall number
40 ori gr10,#CLONE_VM,gr8 ; first syscall arg [clone_flags]
41 sethi.p #0xe4e4,gr9 ; second syscall arg [newsp]
42 setlo #0xe4e4,gr9
43 setlos.p #0,gr10 ; third syscall arg [parent_tidptr]
44 setlos #0,gr11 ; fourth syscall arg [child_tidptr]
45 tira gr0,#0
46 setlos.p #4095,gr7
47 andcc gr8,gr8,gr0,icc0
48 addcc.p gr8,gr7,gr0,icc1
49 bnelr icc0,#2
50 bc icc1,#0,kernel_thread_error
51
52 # now invoke the work function
53 or gr5,gr0,gr8
54 calll @(gr4,gr0)
55
56 # and finally exit the thread
57 setlos #__NR_exit,gr7 ; syscall number
58 tira gr0,#0
59
60kernel_thread_error:
61 subi sp,#8,sp
62 movsg lr,gr4
63 sti gr8,@(sp,#0)
64 sti.p gr4,@(sp,#4)
65
66 or gr8,gr0,gr9
67 sethi.p %hi(kernel_thread_emsg),gr8
68 setlo %lo(kernel_thread_emsg),gr8
69
70 call printk
71
72 ldi @(sp,#4),gr4
73 ldi @(sp,#0),gr8
74 subi sp,#8,sp
75 jmpl @(gr4,gr0)
76
77 .size kernel_thread,.-kernel_thread
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index ff95f50efea..0f02dee25e2 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -37,6 +37,7 @@
37#include "local.h" 37#include "local.h"
38 38
39asmlinkage void ret_from_fork(void); 39asmlinkage void ret_from_fork(void);
40asmlinkage void ret_from_kernel_thread(void);
40 41
41#include <asm/pgalloc.h> 42#include <asm/pgalloc.h>
42 43
@@ -172,29 +173,21 @@ int copy_thread(unsigned long clone_flags,
172 unsigned long usp, unsigned long topstk, 173 unsigned long usp, unsigned long topstk,
173 struct task_struct *p, struct pt_regs *regs) 174 struct task_struct *p, struct pt_regs *regs)
174{ 175{
175 struct pt_regs *childregs0, *childregs, *regs0; 176 struct pt_regs *childregs;
176 177
177 regs0 = __kernel_frame0_ptr; 178 childregs = (struct pt_regs *)
178 childregs0 = (struct pt_regs *)
179 (task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE); 179 (task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
180 childregs = childregs0;
181 180
182 /* set up the userspace frame (the only place that the USP is stored) */ 181 /* set up the userspace frame (the only place that the USP is stored) */
183 *childregs0 = *regs0; 182 *childregs = *regs;
184 183
185 childregs0->gr8 = 0; 184 childregs->sp = usp;
186 childregs0->sp = usp; 185 childregs->next_frame = NULL;
187 childregs0->next_frame = NULL; 186
188 187 if (unlikely(!user_mode(regs)))
189 /* set up the return kernel frame if called from kernel_thread() */ 188 p->thread.pc = (unsigned long) ret_from_kernel_thread;
190 if (regs != regs0) { 189 else
191 childregs--; 190 p->thread.pc = (unsigned long) ret_from_fork;
192 *childregs = *regs;
193 childregs->sp = (unsigned long) childregs0;
194 childregs->next_frame = childregs0;
195 childregs->gr15 = (unsigned long) task_thread_info(p);
196 childregs->gr29 = (unsigned long) p;
197 }
198 191
199 p->set_child_tid = p->clear_child_tid = NULL; 192 p->set_child_tid = p->clear_child_tid = NULL;
200 193
@@ -203,8 +196,7 @@ int copy_thread(unsigned long clone_flags,
203 p->thread.sp = (unsigned long) childregs; 196 p->thread.sp = (unsigned long) childregs;
204 p->thread.fp = 0; 197 p->thread.fp = 0;
205 p->thread.lr = 0; 198 p->thread.lr = 0;
206 p->thread.pc = (unsigned long) ret_from_fork; 199 p->thread.frame0 = childregs;
207 p->thread.frame0 = childregs0;
208 200
209 /* the new TLS pointer is passed in as arg #5 to sys_clone() */ 201 /* the new TLS pointer is passed in as arg #5 to sys_clone() */
210 if (clone_flags & CLONE_SETTLS) 202 if (clone_flags & CLONE_SETTLS)
@@ -347,3 +339,13 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
347 sizeof(current->thread.user->f)); 339 sizeof(current->thread.user->f));
348 return 1; 340 return 1;
349} 341}
342
343int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
344{
345 struct pt_regs regs = {
346 .gr8 = (unsigned long)arg;
347 .gr9 = (unsigned long)fn;
348 .psr = PSR_S;
349 };
350 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
351}