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-v32 | |
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-v32')
-rw-r--r-- | arch/cris/arch-v32/kernel/entry.S | 13 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/process.c | 74 |
2 files changed, 35 insertions, 52 deletions
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index c3ea4694fbaf..a9bcbc419278 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S | |||
@@ -31,6 +31,7 @@ | |||
31 | .globl system_call | 31 | .globl system_call |
32 | .globl ret_from_intr | 32 | .globl ret_from_intr |
33 | .globl ret_from_fork | 33 | .globl ret_from_fork |
34 | .globl ret_from_kernel_thread | ||
34 | .globl resume | 35 | .globl resume |
35 | .globl multiple_interrupt | 36 | .globl multiple_interrupt |
36 | .globl nmi_interrupt | 37 | .globl nmi_interrupt |
@@ -84,6 +85,18 @@ ret_from_fork: | |||
84 | nop | 85 | nop |
85 | .size ret_from_fork, . - ret_from_fork | 86 | .size ret_from_fork, . - ret_from_fork |
86 | 87 | ||
88 | .type ret_from_kernel_thread,@function | ||
89 | ret_from_kernel_thread: | ||
90 | jsr schedule_tail | ||
91 | nop | ||
92 | move.d $r2, $r10 | ||
93 | jsr $r1 | ||
94 | nop | ||
95 | moveq 0, $r10 | ||
96 | jsr sys_exit | ||
97 | nop | ||
98 | .size ret_from_kernel_thread, . - ret_from_kernel_thread | ||
99 | |||
87 | .type ret_from_intr,@function | 100 | .type ret_from_intr,@function |
88 | ret_from_intr: | 101 | ret_from_intr: |
89 | ;; Check for resched if preemptive kernel, or if we're going back to | 102 | ;; Check for resched if preemptive kernel, or if we're going back to |
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index 4e9992246359..3edbdb88110e 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <hwregs/reg_map.h> | 16 | #include <hwregs/reg_map.h> |
17 | #include <hwregs/timer_defs.h> | 17 | #include <hwregs/timer_defs.h> |
18 | #include <hwregs/intr_vect_defs.h> | 18 | #include <hwregs/intr_vect_defs.h> |
19 | #include <asm/ptrace.h> | ||
19 | 20 | ||
20 | extern void stop_watchdog(void); | 21 | extern void stop_watchdog(void); |
21 | 22 | ||
@@ -94,31 +95,6 @@ unsigned long thread_saved_pc(struct task_struct *t) | |||
94 | return task_pt_regs(t)->erp; | 95 | return task_pt_regs(t)->erp; |
95 | } | 96 | } |
96 | 97 | ||
97 | static void | ||
98 | kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) | ||
99 | { | ||
100 | fn(arg); | ||
101 | do_exit(-1); /* Should never be called, return bad exit value. */ | ||
102 | } | ||
103 | |||
104 | /* Create a kernel thread. */ | ||
105 | int | ||
106 | kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
107 | { | ||
108 | struct pt_regs regs; | ||
109 | |||
110 | memset(®s, 0, sizeof(regs)); | ||
111 | |||
112 | /* Don't use r10 since that is set to 0 in copy_thread. */ | ||
113 | regs.r11 = (unsigned long) fn; | ||
114 | regs.r12 = (unsigned long) arg; | ||
115 | regs.erp = (unsigned long) kernel_thread_helper; | ||
116 | regs.ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); | ||
117 | |||
118 | /* Create the new process. */ | ||
119 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
120 | } | ||
121 | |||
122 | /* | 98 | /* |
123 | * Setup the child's kernel stack with a pt_regs and call switch_stack() on it. | 99 | * Setup the child's kernel stack with a pt_regs and call switch_stack() on it. |
124 | * It will be unnested during _resume and _ret_from_sys_call when the new thread | 100 | * It will be unnested during _resume and _ret_from_sys_call when the new thread |
@@ -129,23 +105,33 @@ kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
129 | */ | 105 | */ |
130 | 106 | ||
131 | extern asmlinkage void ret_from_fork(void); | 107 | extern asmlinkage void ret_from_fork(void); |
108 | extern asmlinkage void ret_from_kernel_thread(void); | ||
132 | 109 | ||
133 | int | 110 | int |
134 | copy_thread(unsigned long clone_flags, unsigned long usp, | 111 | copy_thread(unsigned long clone_flags, unsigned long usp, |
135 | unsigned long unused, | 112 | unsigned long arg, |
136 | struct task_struct *p, struct pt_regs *regs) | 113 | struct task_struct *p, struct pt_regs *regs) |
137 | { | 114 | { |
138 | struct pt_regs *childregs; | 115 | struct pt_regs *childregs = task_pt_regs(p); |
139 | struct switch_stack *swstack; | 116 | struct switch_stack *swstack = ((struct switch_stack *) childregs) - 1; |
140 | 117 | ||
141 | /* | 118 | /* |
142 | * Put the pt_regs structure at the end of the new kernel stack page and | 119 | * Put the pt_regs structure at the end of the new kernel stack page and |
143 | * fix it up. Note: the task_struct doubles as the kernel stack for the | 120 | * fix it up. Note: the task_struct doubles as the kernel stack for the |
144 | * task. | 121 | * task. |
145 | */ | 122 | */ |
146 | childregs = task_pt_regs(p); | 123 | if (unlikely(p->flags & PF_KTHREAD)) { |
124 | memset(swstack, 0, | ||
125 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | ||
126 | swstack->r1 = usp; | ||
127 | swstack->r2 = arg; | ||
128 | childregs->ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); | ||
129 | swstack->return_ip = (unsigned long) ret_from_kernel_thread; | ||
130 | p->thread.ksp = (unsigned long) swstack; | ||
131 | p->thread.usp = 0; | ||
132 | return 0; | ||
133 | } | ||
147 | *childregs = *regs; /* Struct copy of pt_regs. */ | 134 | *childregs = *regs; /* Struct copy of pt_regs. */ |
148 | p->set_child_tid = p->clear_child_tid = NULL; | ||
149 | childregs->r10 = 0; /* Child returns 0 after a fork/clone. */ | 135 | childregs->r10 = 0; /* Child returns 0 after a fork/clone. */ |
150 | 136 | ||
151 | /* Set a new TLS ? | 137 | /* Set a new TLS ? |
@@ -156,7 +142,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
156 | } | 142 | } |
157 | 143 | ||
158 | /* Put the switch stack right below the pt_regs. */ | 144 | /* Put the switch stack right below the pt_regs. */ |
159 | swstack = ((struct switch_stack *) childregs) - 1; | ||
160 | 145 | ||
161 | /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */ | 146 | /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */ |
162 | swstack->r9 = 0; | 147 | swstack->r9 = 0; |
@@ -174,35 +159,21 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
174 | return 0; | 159 | return 0; |
175 | } | 160 | } |
176 | 161 | ||
177 | /* | ||
178 | * Be aware of the "magic" 7th argument in the four system-calls below. | ||
179 | * They need the latest stackframe, which is put as the 7th argument by | ||
180 | * entry.S. The previous arguments are dummies or actually used, but need | ||
181 | * to be defined to reach the 7th argument. | ||
182 | * | ||
183 | * N.B.: Another method to get the stackframe is to use current_regs(). But | ||
184 | * it returns the latest stack-frame stacked when going from _user mode_ and | ||
185 | * some of these (at least sys_clone) are called from kernel-mode sometimes | ||
186 | * (for example during kernel_thread, above) and thus cannot use it. Thus, | ||
187 | * to be sure not to get any surprises, we use the method for the other calls | ||
188 | * as well. | ||
189 | */ | ||
190 | asmlinkage int | 162 | asmlinkage int |
191 | sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, | 163 | sys_fork(void) |
192 | struct pt_regs *regs) | ||
193 | { | 164 | { |
194 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | 165 | return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
195 | } | 166 | } |
196 | 167 | ||
197 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ | 168 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ |
198 | asmlinkage int | 169 | asmlinkage int |
199 | sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child_tid, | 170 | sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child_tid, |
200 | unsigned long tls, long srp, struct pt_regs *regs) | 171 | unsigned long tls) |
201 | { | 172 | { |
202 | if (!newusp) | 173 | if (!newusp) |
203 | newusp = rdusp(); | 174 | newusp = rdusp(); |
204 | 175 | ||
205 | return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); | 176 | return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid); |
206 | } | 177 | } |
207 | 178 | ||
208 | /* | 179 | /* |
@@ -210,10 +181,9 @@ sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child | |||
210 | * we can remove it and handle it in libc but we put it here until then. | 181 | * we can remove it and handle it in libc but we put it here until then. |
211 | */ | 182 | */ |
212 | asmlinkage int | 183 | asmlinkage int |
213 | sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, | 184 | sys_vfork(void) |
214 | struct pt_regs *regs) | ||
215 | { | 185 | { |
216 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | 186 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
217 | } | 187 | } |
218 | 188 | ||
219 | /* sys_execve() executes a new program. */ | 189 | /* sys_execve() executes a new program. */ |