diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-06 13:52:37 -0400 |
---|---|---|
committer | Michal Simek <michal.simek@xilinx.com> | 2012-11-16 02:44:57 -0500 |
commit | 2319295dd8dbd076afa136bffb797ef726b605a0 (patch) | |
tree | 9699149edbd77d16d8c41914677068ab6cde167c /arch/microblaze | |
parent | fd11ff7380fe7c61f55e6caf33982edeab3fbc19 (diff) |
microblaze: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Diffstat (limited to 'arch/microblaze')
-rw-r--r-- | arch/microblaze/Kconfig | 1 | ||||
-rw-r--r-- | arch/microblaze/include/asm/processor.h | 8 | ||||
-rw-r--r-- | arch/microblaze/kernel/entry-nommu.S | 8 | ||||
-rw-r--r-- | arch/microblaze/kernel/entry.S | 9 | ||||
-rw-r--r-- | arch/microblaze/kernel/process.c | 71 |
5 files changed, 39 insertions, 58 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 4cba7439f9de..3b8df669eecd 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig | |||
@@ -26,6 +26,7 @@ config MICROBLAZE | |||
26 | select GENERIC_ATOMIC64 | 26 | select GENERIC_ATOMIC64 |
27 | select GENERIC_CLOCKEVENTS | 27 | select GENERIC_CLOCKEVENTS |
28 | select MODULES_USE_ELF_RELA | 28 | select MODULES_USE_ELF_RELA |
29 | select GENERIC_KERNEL_THREAD | ||
29 | 30 | ||
30 | config SWAP | 31 | config SWAP |
31 | def_bool n | 32 | def_bool n |
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index af2bb9652392..0759153e8117 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h | |||
@@ -31,6 +31,7 @@ extern const struct seq_operations cpuinfo_op; | |||
31 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp); | 31 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp); |
32 | 32 | ||
33 | extern void ret_from_fork(void); | 33 | extern void ret_from_fork(void); |
34 | extern void ret_from_kernel_thread(void); | ||
34 | 35 | ||
35 | # endif /* __ASSEMBLY__ */ | 36 | # endif /* __ASSEMBLY__ */ |
36 | 37 | ||
@@ -78,11 +79,6 @@ extern unsigned long thread_saved_pc(struct task_struct *t); | |||
78 | 79 | ||
79 | extern unsigned long get_wchan(struct task_struct *p); | 80 | extern unsigned long get_wchan(struct task_struct *p); |
80 | 81 | ||
81 | /* | ||
82 | * create a kernel thread without removing it from tasklists | ||
83 | */ | ||
84 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
85 | |||
86 | # define KSTK_EIP(tsk) (0) | 82 | # define KSTK_EIP(tsk) (0) |
87 | # define KSTK_ESP(tsk) (0) | 83 | # define KSTK_ESP(tsk) (0) |
88 | 84 | ||
@@ -131,8 +127,6 @@ extern inline void release_thread(struct task_struct *dead_task) | |||
131 | { | 127 | { |
132 | } | 128 | } |
133 | 129 | ||
134 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
135 | |||
136 | /* Free current thread data structures etc. */ | 130 | /* Free current thread data structures etc. */ |
137 | static inline void exit_thread(void) | 131 | static inline void exit_thread(void) |
138 | { | 132 | { |
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 75c3ea1f48a1..c47e92cd7e78 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S | |||
@@ -474,6 +474,14 @@ ENTRY(ret_from_fork) | |||
474 | brid ret_to_user | 474 | brid ret_to_user |
475 | nop | 475 | nop |
476 | 476 | ||
477 | ENTRY(ret_from_kernel_thread) | ||
478 | brlid r15, schedule_tail | ||
479 | addk r5, r0, r3 | ||
480 | brald r15, r20 | ||
481 | addk r5, r0, r19 | ||
482 | brid sys_exit /* won't be returning... */ | ||
483 | addk r5, r0, r0 | ||
484 | |||
477 | work_pending: | 485 | work_pending: |
478 | enable_irq | 486 | enable_irq |
479 | 487 | ||
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 1cf702ab7463..be76d1338be0 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -484,6 +484,15 @@ C_ENTRY(ret_from_fork): | |||
484 | brid ret_from_trap; /* Do normal trap return */ | 484 | brid ret_from_trap; /* Do normal trap return */ |
485 | add r3, r0, r0; /* Child's fork call should return 0. */ | 485 | add r3, r0, r0; /* Child's fork call should return 0. */ |
486 | 486 | ||
487 | C_ENTRY(ret_from_kernel_thread): | ||
488 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ | ||
489 | add r5, r3, r0; /* switch_thread returns the prev task */ | ||
490 | /* ( in the delay slot ) */ | ||
491 | brald r15, r20 /* fn was left in r20 */ | ||
492 | addk r5, r0, r19 /* ... and argument - in r19 */ | ||
493 | brid sys_exit /* won't be returning... */ | ||
494 | addk r5, r0, r0 | ||
495 | |||
487 | C_ENTRY(sys_vfork): | 496 | C_ENTRY(sys_vfork): |
488 | brid microblaze_vfork /* Do real work (tail-call) */ | 497 | brid microblaze_vfork /* Do real work (tail-call) */ |
489 | addik r5, r1, 0 | 498 | addik r5, r1, 0 |
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 1944e00f07e1..cbf8bb92f159 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c | |||
@@ -119,46 +119,38 @@ void flush_thread(void) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 121 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
122 | unsigned long unused, | 122 | unsigned long arg, |
123 | struct task_struct *p, struct pt_regs *regs) | 123 | struct task_struct *p, struct pt_regs *regs) |
124 | { | 124 | { |
125 | struct pt_regs *childregs = task_pt_regs(p); | 125 | struct pt_regs *childregs = task_pt_regs(p); |
126 | struct thread_info *ti = task_thread_info(p); | 126 | struct thread_info *ti = task_thread_info(p); |
127 | 127 | ||
128 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
129 | /* if we're creating a new kernel thread then just zeroing all | ||
130 | * the registers. That's OK for a brand new thread.*/ | ||
131 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
132 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | ||
133 | ti->cpu_context.r1 = (unsigned long)childregs; | ||
134 | ti->cpu_context.r20 = (unsigned long)usp; /* fn */ | ||
135 | ti->cpu_context.r19 = (unsigned long)arg; | ||
136 | childregs->pt_mode = 1; | ||
137 | local_save_flags(childregs->msr); | ||
138 | #ifdef CONFIG_MMU | ||
139 | ti->cpu_context.msr = childregs->msr & ~MSR_IE; | ||
140 | #endif | ||
141 | ti->cpu_context.r15 = (unsigned long)ret_from_kernel_thread - 8; | ||
142 | return 0; | ||
143 | } | ||
128 | *childregs = *regs; | 144 | *childregs = *regs; |
129 | if (user_mode(regs)) | 145 | childregs->r1 = usp; |
130 | childregs->r1 = usp; | ||
131 | else | ||
132 | childregs->r1 = ((unsigned long) ti) + THREAD_SIZE; | ||
133 | 146 | ||
134 | #ifndef CONFIG_MMU | ||
135 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | 147 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); |
136 | ti->cpu_context.r1 = (unsigned long)childregs; | 148 | ti->cpu_context.r1 = (unsigned long)childregs; |
149 | #ifndef CONFIG_MMU | ||
137 | ti->cpu_context.msr = (unsigned long)childregs->msr; | 150 | ti->cpu_context.msr = (unsigned long)childregs->msr; |
138 | #else | 151 | #else |
152 | childregs->msr |= MSR_UMS; | ||
139 | 153 | ||
140 | /* if creating a kernel thread then update the current reg (we don't | ||
141 | * want to use the parent's value when restoring by POP_STATE) */ | ||
142 | if (kernel_mode(regs)) | ||
143 | /* save new current on stack to use POP_STATE */ | ||
144 | childregs->CURRENT_TASK = (unsigned long)p; | ||
145 | /* if returning to user then use the parent's value of this register */ | ||
146 | |||
147 | /* if we're creating a new kernel thread then just zeroing all | ||
148 | * the registers. That's OK for a brand new thread.*/ | ||
149 | /* Pls. note that some of them will be restored in POP_STATE */ | ||
150 | if (kernel_mode(regs)) | ||
151 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | ||
152 | /* if this thread is created for fork/vfork/clone, then we want to | ||
153 | * restore all the parent's context */ | ||
154 | /* in addition to the registers which will be restored by POP_STATE */ | ||
155 | else { | ||
156 | ti->cpu_context = *(struct cpu_context *)regs; | ||
157 | childregs->msr |= MSR_UMS; | ||
158 | } | ||
159 | |||
160 | /* FIXME STATE_SAVE_PT_OFFSET; */ | ||
161 | ti->cpu_context.r1 = (unsigned long)childregs; | ||
162 | /* we should consider the fact that childregs is a copy of the parent | 154 | /* we should consider the fact that childregs is a copy of the parent |
163 | * regs which were saved immediately after entering the kernel state | 155 | * regs which were saved immediately after entering the kernel state |
164 | * before enabling VM. This MSR will be restored in switch_to and | 156 | * before enabling VM. This MSR will be restored in switch_to and |
@@ -209,29 +201,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
209 | } | 201 | } |
210 | #endif | 202 | #endif |
211 | 203 | ||
212 | static void kernel_thread_helper(int (*fn)(void *), void *arg) | ||
213 | { | ||
214 | fn(arg); | ||
215 | do_exit(-1); | ||
216 | } | ||
217 | |||
218 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
219 | { | ||
220 | struct pt_regs regs; | ||
221 | |||
222 | memset(®s, 0, sizeof(regs)); | ||
223 | /* store them in non-volatile registers */ | ||
224 | regs.r5 = (unsigned long)fn; | ||
225 | regs.r6 = (unsigned long)arg; | ||
226 | local_save_flags(regs.msr); | ||
227 | regs.pc = (unsigned long)kernel_thread_helper; | ||
228 | regs.pt_mode = 1; | ||
229 | |||
230 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | ||
231 | ®s, 0, NULL, NULL); | ||
232 | } | ||
233 | EXPORT_SYMBOL_GPL(kernel_thread); | ||
234 | |||
235 | unsigned long get_wchan(struct task_struct *p) | 204 | unsigned long get_wchan(struct task_struct *p) |
236 | { | 205 | { |
237 | /* TBD (used by procfs) */ | 206 | /* TBD (used by procfs) */ |