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 | |
| parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) | |
mips: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | arch/mips/Kconfig | 1 | ||||
| -rw-r--r-- | arch/mips/include/asm/processor.h | 2 | ||||
| -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 |
5 files changed, 30 insertions, 44 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index dba9390d37cf..ede301f9c88b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
| @@ -40,6 +40,7 @@ config MIPS | |||
| 40 | select HAVE_MOD_ARCH_SPECIFIC | 40 | select HAVE_MOD_ARCH_SPECIFIC |
| 41 | select MODULES_USE_ELF_REL | 41 | select MODULES_USE_ELF_REL |
| 42 | select MODULES_USE_ELF_RELA if 64BIT | 42 | select MODULES_USE_ELF_RELA if 64BIT |
| 43 | select GENERIC_KERNEL_THREAD | ||
| 43 | 44 | ||
| 44 | menu "Machine selection" | 45 | menu "Machine selection" |
| 45 | 46 | ||
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 5e33fabe354d..d28c41e0887c 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h | |||
| @@ -310,8 +310,6 @@ struct task_struct; | |||
| 310 | /* Free all resources held by a thread. */ | 310 | /* Free all resources held by a thread. */ |
| 311 | #define release_thread(thread) do { } while(0) | 311 | #define release_thread(thread) do { } while(0) |
| 312 | 312 | ||
| 313 | extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
| 314 | |||
| 315 | extern unsigned long thread_saved_pc(struct task_struct *tsk); | 313 | extern unsigned long thread_saved_pc(struct task_struct *tsk); |
| 316 | 314 | ||
| 317 | /* | 315 | /* |
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 { |
