diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-09 16:27:45 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-14 19:30:25 -0400 |
commit | 8f54bcacbc39f883bde2210cf2754e5d198f55a4 (patch) | |
tree | 1ed53a3cf864bd6372021d4384b70070da23345c /arch/mips/kernel | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) |
mips: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/entry.S | 7 | ||||
-rw-r--r-- | arch/mips/kernel/mips_ksyms.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 62 |
3 files changed, 29 insertions, 42 deletions
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index a6c133212003..aab6997b8f47 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S | |||
@@ -65,6 +65,13 @@ need_resched: | |||
65 | b need_resched | 65 | b need_resched |
66 | #endif | 66 | #endif |
67 | 67 | ||
68 | FEXPORT(ret_from_kernel_thread) | ||
69 | jal schedule_tail # a0 = struct task_struct *prev | ||
70 | move a0, s1 | ||
71 | jal s0 | ||
72 | li a0, 0 | ||
73 | j sys_exit | ||
74 | |||
68 | FEXPORT(ret_from_fork) | 75 | FEXPORT(ret_from_fork) |
69 | jal schedule_tail # a0 = struct task_struct *prev | 76 | jal schedule_tail # a0 = struct task_struct *prev |
70 | 77 | ||
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 3fc1691110dc..2d9304c2b54c 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c | |||
@@ -32,8 +32,6 @@ EXPORT_SYMBOL(memset); | |||
32 | EXPORT_SYMBOL(memcpy); | 32 | EXPORT_SYMBOL(memcpy); |
33 | EXPORT_SYMBOL(memmove); | 33 | EXPORT_SYMBOL(memmove); |
34 | 34 | ||
35 | EXPORT_SYMBOL(kernel_thread); | ||
36 | |||
37 | /* | 35 | /* |
38 | * Functions that operate on entire pages. Mostly used by memory management. | 36 | * Functions that operate on entire pages. Mostly used by memory management. |
39 | */ | 37 | */ |
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index e9a5fd7277f4..d13720ac656f 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -84,6 +84,7 @@ void __noreturn cpu_idle(void) | |||
84 | } | 84 | } |
85 | 85 | ||
86 | asmlinkage void ret_from_fork(void); | 86 | asmlinkage void ret_from_fork(void); |
87 | asmlinkage void ret_from_kernel_thread(void); | ||
87 | 88 | ||
88 | void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) | 89 | void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) |
89 | { | 90 | { |
@@ -113,7 +114,7 @@ void flush_thread(void) | |||
113 | } | 114 | } |
114 | 115 | ||
115 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 116 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
116 | unsigned long unused, struct task_struct *p, struct pt_regs *regs) | 117 | unsigned long arg, struct task_struct *p, struct pt_regs *regs) |
117 | { | 118 | { |
118 | struct thread_info *ti = task_thread_info(p); | 119 | struct thread_info *ti = task_thread_info(p); |
119 | struct pt_regs *childregs; | 120 | struct pt_regs *childregs; |
@@ -136,19 +137,30 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
136 | childregs = (struct pt_regs *) childksp - 1; | 137 | childregs = (struct pt_regs *) childksp - 1; |
137 | /* Put the stack after the struct pt_regs. */ | 138 | /* Put the stack after the struct pt_regs. */ |
138 | childksp = (unsigned long) childregs; | 139 | childksp = (unsigned long) childregs; |
140 | p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1); | ||
141 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
142 | unsigned long status = p->thread.cp0_status; | ||
143 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
144 | ti->addr_limit = KERNEL_DS; | ||
145 | p->thread.reg16 = usp; /* fn */ | ||
146 | p->thread.reg17 = arg; | ||
147 | p->thread.reg29 = childksp; | ||
148 | p->thread.reg31 = (unsigned long) ret_from_kernel_thread; | ||
149 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | ||
150 | status = (status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) | | ||
151 | ((status & (ST0_KUC | ST0_IEC)) << 2); | ||
152 | #else | ||
153 | status |= ST0_EXL; | ||
154 | #endif | ||
155 | childregs->cp0_status = status; | ||
156 | return 0; | ||
157 | } | ||
139 | *childregs = *regs; | 158 | *childregs = *regs; |
140 | childregs->regs[7] = 0; /* Clear error flag */ | 159 | childregs->regs[7] = 0; /* Clear error flag */ |
141 | |||
142 | childregs->regs[2] = 0; /* Child gets zero as return value */ | 160 | childregs->regs[2] = 0; /* Child gets zero as return value */ |
161 | childregs->regs[29] = usp; | ||
162 | ti->addr_limit = USER_DS; | ||
143 | 163 | ||
144 | if (childregs->cp0_status & ST0_CU0) { | ||
145 | childregs->regs[28] = (unsigned long) ti; | ||
146 | childregs->regs[29] = childksp; | ||
147 | ti->addr_limit = KERNEL_DS; | ||
148 | } else { | ||
149 | childregs->regs[29] = usp; | ||
150 | ti->addr_limit = USER_DS; | ||
151 | } | ||
152 | p->thread.reg29 = (unsigned long) childregs; | 164 | p->thread.reg29 = (unsigned long) childregs; |
153 | p->thread.reg31 = (unsigned long) ret_from_fork; | 165 | p->thread.reg31 = (unsigned long) ret_from_fork; |
154 | 166 | ||
@@ -156,7 +168,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
156 | * New tasks lose permission to use the fpu. This accelerates context | 168 | * New tasks lose permission to use the fpu. This accelerates context |
157 | * switching for most programs since they don't use the fpu. | 169 | * switching for most programs since they don't use the fpu. |
158 | */ | 170 | */ |
159 | p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1); | ||
160 | childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); | 171 | childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); |
161 | 172 | ||
162 | #ifdef CONFIG_MIPS_MT_SMTC | 173 | #ifdef CONFIG_MIPS_MT_SMTC |
@@ -222,35 +233,6 @@ int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr) | |||
222 | } | 233 | } |
223 | 234 | ||
224 | /* | 235 | /* |
225 | * Create a kernel thread | ||
226 | */ | ||
227 | static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *)) | ||
228 | { | ||
229 | do_exit(fn(arg)); | ||
230 | } | ||
231 | |||
232 | long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
233 | { | ||
234 | struct pt_regs regs; | ||
235 | |||
236 | memset(®s, 0, sizeof(regs)); | ||
237 | |||
238 | regs.regs[4] = (unsigned long) arg; | ||
239 | regs.regs[5] = (unsigned long) fn; | ||
240 | regs.cp0_epc = (unsigned long) kernel_thread_helper; | ||
241 | regs.cp0_status = read_c0_status(); | ||
242 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | ||
243 | regs.cp0_status = (regs.cp0_status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) | | ||
244 | ((regs.cp0_status & (ST0_KUC | ST0_IEC)) << 2); | ||
245 | #else | ||
246 | regs.cp0_status |= ST0_EXL; | ||
247 | #endif | ||
248 | |||
249 | /* Ok, create the new process.. */ | ||
250 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * | 236 | * |
255 | */ | 237 | */ |
256 | struct mips_frame_info { | 238 | struct mips_frame_info { |