diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-03 14:46:55 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-14 23:12:25 -0400 |
commit | 69b58a67213506f98835b0ee8cf24324f59a1442 (patch) | |
tree | 554e56ac841e958398b0967784db8628dbbf48a3 /arch/cris/arch-v10/kernel | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) |
cris: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/cris/arch-v10/kernel')
-rw-r--r-- | arch/cris/arch-v10/kernel/entry.S | 10 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/process.c | 83 |
2 files changed, 33 insertions, 60 deletions
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 592fbe9dfb62..b8e39e00acb2 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S | |||
@@ -35,6 +35,7 @@ | |||
35 | .globl system_call | 35 | .globl system_call |
36 | .globl ret_from_intr | 36 | .globl ret_from_intr |
37 | .globl ret_from_fork | 37 | .globl ret_from_fork |
38 | .globl ret_from_kernel_thread | ||
38 | .globl resume | 39 | .globl resume |
39 | .globl multiple_interrupt | 40 | .globl multiple_interrupt |
40 | .globl hwbreakpoint | 41 | .globl hwbreakpoint |
@@ -81,7 +82,14 @@ ret_from_fork: | |||
81 | jsr schedule_tail | 82 | jsr schedule_tail |
82 | ba ret_from_sys_call | 83 | ba ret_from_sys_call |
83 | nop | 84 | nop |
84 | 85 | ||
86 | ret_from_kernel_thread: | ||
87 | jsr schedule_tail | ||
88 | move.d $r2, $r10 ; argument is here | ||
89 | jsr $r1 ; call the payload | ||
90 | moveq 0, $r10 | ||
91 | jsr sys_exit ; never returns | ||
92 | |||
85 | ret_from_intr: | 93 | ret_from_intr: |
86 | ;; check for resched if preemptive kernel or if we're going back to user-mode | 94 | ;; check for resched if preemptive kernel or if we're going back to user-mode |
87 | ;; this test matches the user_regs(regs) macro | 95 | ;; this test matches the user_regs(regs) macro |
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 15ac7150371f..8a673aa81cdd 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <arch/svinto.h> | 17 | #include <arch/svinto.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <arch/system.h> | 19 | #include <arch/system.h> |
20 | #include <asm/ptrace.h> | ||
20 | 21 | ||
21 | #ifdef CONFIG_ETRAX_GPIO | 22 | #ifdef CONFIG_ETRAX_GPIO |
22 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ | 23 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ |
@@ -81,31 +82,6 @@ unsigned long thread_saved_pc(struct task_struct *t) | |||
81 | return task_pt_regs(t)->irp; | 82 | return task_pt_regs(t)->irp; |
82 | } | 83 | } |
83 | 84 | ||
84 | static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) | ||
85 | { | ||
86 | fn(arg); | ||
87 | do_exit(-1); /* Should never be called, return bad exit value */ | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Create a kernel thread | ||
92 | */ | ||
93 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
94 | { | ||
95 | struct pt_regs regs; | ||
96 | |||
97 | memset(®s, 0, sizeof(regs)); | ||
98 | |||
99 | /* Don't use r10 since that is set to 0 in copy_thread */ | ||
100 | regs.r11 = (unsigned long)fn; | ||
101 | regs.r12 = (unsigned long)arg; | ||
102 | regs.irp = (unsigned long)kernel_thread_helper; | ||
103 | regs.dccr = 1 << I_DCCR_BITNR; | ||
104 | |||
105 | /* Ok, create the new process.. */ | ||
106 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
107 | } | ||
108 | |||
109 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. | 85 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. |
110 | * it will be un-nested during _resume and _ret_from_sys_call when the | 86 | * it will be un-nested during _resume and _ret_from_sys_call when the |
111 | * new thread is scheduled. | 87 | * new thread is scheduled. |
@@ -115,29 +91,35 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
115 | * | 91 | * |
116 | */ | 92 | */ |
117 | asmlinkage void ret_from_fork(void); | 93 | asmlinkage void ret_from_fork(void); |
94 | asmlinkage void ret_from_kernel_thread(void); | ||
118 | 95 | ||
119 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 96 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
120 | unsigned long unused, | 97 | unsigned long arg, |
121 | struct task_struct *p, struct pt_regs *regs) | 98 | struct task_struct *p, struct pt_regs *regs) |
122 | { | 99 | { |
123 | struct pt_regs * childregs; | 100 | struct pt_regs *childregs = task_pt_regs(p); |
124 | struct switch_stack *swstack; | 101 | struct switch_stack *swstack = ((struct switch_stack *)childregs) - 1; |
125 | 102 | ||
126 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up | 103 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up |
127 | * remember that the task_struct doubles as the kernel stack for the task | 104 | * remember that the task_struct doubles as the kernel stack for the task |
128 | */ | 105 | */ |
129 | 106 | ||
130 | childregs = task_pt_regs(p); | 107 | if (unlikely(p->flags & PF_KTHREAD)) { |
131 | 108 | memset(swstack, 0, | |
109 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | ||
110 | swstack->r1 = usp; | ||
111 | swstack->r2 = arg; | ||
112 | childregs->dccr = 1 << I_DCCR_BITNR; | ||
113 | swstack->return_ip = (unsigned long) ret_from_kernel_thread; | ||
114 | p->thread.ksp = (unsigned long) swstack; | ||
115 | p->thread.usp = 0; | ||
116 | return 0; | ||
117 | } | ||
132 | *childregs = *regs; /* struct copy of pt_regs */ | 118 | *childregs = *regs; /* struct copy of pt_regs */ |
133 | |||
134 | p->set_child_tid = p->clear_child_tid = NULL; | ||
135 | 119 | ||
136 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ | 120 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ |
137 | |||
138 | /* put the switch stack right below the pt_regs */ | ||
139 | 121 | ||
140 | swstack = ((struct switch_stack *)childregs) - 1; | 122 | /* put the switch stack right below the pt_regs */ |
141 | 123 | ||
142 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ | 124 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ |
143 | 125 | ||
@@ -147,7 +129,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
147 | 129 | ||
148 | /* fix the user-mode stackpointer */ | 130 | /* fix the user-mode stackpointer */ |
149 | 131 | ||
150 | p->thread.usp = usp; | 132 | p->thread.usp = usp; |
151 | 133 | ||
152 | /* and the kernel-mode one */ | 134 | /* and the kernel-mode one */ |
153 | 135 | ||
@@ -161,45 +143,28 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
161 | return 0; | 143 | return 0; |
162 | } | 144 | } |
163 | 145 | ||
164 | /* | 146 | asmlinkage int sys_fork(void) |
165 | * Be aware of the "magic" 7th argument in the four system-calls below. | ||
166 | * They need the latest stackframe, which is put as the 7th argument by | ||
167 | * entry.S. The previous arguments are dummies or actually used, but need | ||
168 | * to be defined to reach the 7th argument. | ||
169 | * | ||
170 | * N.B.: Another method to get the stackframe is to use current_regs(). But | ||
171 | * it returns the latest stack-frame stacked when going from _user mode_ and | ||
172 | * some of these (at least sys_clone) are called from kernel-mode sometimes | ||
173 | * (for example during kernel_thread, above) and thus cannot use it. Thus, | ||
174 | * to be sure not to get any surprises, we use the method for the other calls | ||
175 | * as well. | ||
176 | */ | ||
177 | |||
178 | asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
179 | struct pt_regs *regs) | ||
180 | { | 147 | { |
181 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | 148 | return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
182 | } | 149 | } |
183 | 150 | ||
184 | /* if newusp is 0, we just grab the old usp */ | 151 | /* if newusp is 0, we just grab the old usp */ |
185 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ | 152 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ |
186 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, | 153 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, |
187 | int* parent_tid, int* child_tid, long mof, long srp, | 154 | int* parent_tid, int* child_tid) |
188 | struct pt_regs *regs) | ||
189 | { | 155 | { |
190 | if (!newusp) | 156 | if (!newusp) |
191 | newusp = rdusp(); | 157 | newusp = rdusp(); |
192 | return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); | 158 | return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid); |
193 | } | 159 | } |
194 | 160 | ||
195 | /* vfork is a system call in i386 because of register-pressure - maybe | 161 | /* vfork is a system call in i386 because of register-pressure - maybe |
196 | * we can remove it and handle it in libc but we put it here until then. | 162 | * we can remove it and handle it in libc but we put it here until then. |
197 | */ | 163 | */ |
198 | 164 | ||
199 | asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, | 165 | asmlinkage int sys_vfork(void) |
200 | struct pt_regs *regs) | ||
201 | { | 166 | { |
202 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | 167 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
203 | } | 168 | } |
204 | 169 | ||
205 | /* | 170 | /* |