diff options
Diffstat (limited to 'arch/microblaze/kernel')
-rw-r--r-- | arch/microblaze/kernel/entry-nommu.S | 12 | ||||
-rw-r--r-- | arch/microblaze/kernel/entry.S | 33 | ||||
-rw-r--r-- | arch/microblaze/kernel/process.c | 72 | ||||
-rw-r--r-- | arch/microblaze/kernel/sys_microblaze.c | 39 |
4 files changed, 39 insertions, 117 deletions
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 75c3ea1f48a1..673a49c04a02 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 ret_to_user | ||
483 | addk r3, r0, r0 | ||
484 | |||
477 | work_pending: | 485 | work_pending: |
478 | enable_irq | 486 | enable_irq |
479 | 487 | ||
@@ -559,10 +567,6 @@ sys_clone: | |||
559 | brid microblaze_clone | 567 | brid microblaze_clone |
560 | addk r7, r1, r0 | 568 | addk r7, r1, r0 |
561 | 569 | ||
562 | sys_execve: | ||
563 | brid microblaze_execve | ||
564 | addk r8, r1, r0 | ||
565 | |||
566 | sys_rt_sigreturn_wrapper: | 570 | sys_rt_sigreturn_wrapper: |
567 | brid sys_rt_sigreturn | 571 | brid sys_rt_sigreturn |
568 | addk r5, r1, r0 | 572 | addk r5, r1, r0 |
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 03f7b8ce6b6b..10f360ed82b4 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -293,24 +293,6 @@ C_ENTRY(_user_exception): | |||
293 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ | 293 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ |
294 | addi r14, r14, 4 /* return address is 4 byte after call */ | 294 | addi r14, r14, 4 /* return address is 4 byte after call */ |
295 | 295 | ||
296 | mfs r1, rmsr | ||
297 | nop | ||
298 | andi r1, r1, MSR_UMS | ||
299 | bnei r1, 1f | ||
300 | |||
301 | /* Kernel-mode state save - kernel execve */ | ||
302 | lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ | ||
303 | tophys(r1,r1); | ||
304 | |||
305 | addik r1, r1, -PT_SIZE; /* Make room on the stack. */ | ||
306 | SAVE_REGS | ||
307 | |||
308 | swi r1, r1, PT_MODE; /* pt_regs -> kernel mode */ | ||
309 | brid 2f; | ||
310 | nop; /* Fill delay slot */ | ||
311 | |||
312 | /* User-mode state save. */ | ||
313 | 1: | ||
314 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ | 296 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ |
315 | tophys(r1,r1); | 297 | tophys(r1,r1); |
316 | lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ | 298 | lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ |
@@ -479,11 +461,20 @@ C_ENTRY(sys_fork_wrapper): | |||
479 | saved context). */ | 461 | saved context). */ |
480 | C_ENTRY(ret_from_fork): | 462 | C_ENTRY(ret_from_fork): |
481 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ | 463 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ |
482 | add r3, r5, r0; /* switch_thread returns the prev task */ | 464 | add r5, r3, r0; /* switch_thread returns the prev task */ |
483 | /* ( in the delay slot ) */ | 465 | /* ( in the delay slot ) */ |
484 | brid ret_from_trap; /* Do normal trap return */ | 466 | brid ret_from_trap; /* Do normal trap return */ |
485 | add r3, r0, r0; /* Child's fork call should return 0. */ | 467 | add r3, r0, r0; /* Child's fork call should return 0. */ |
486 | 468 | ||
469 | C_ENTRY(ret_from_kernel_thread): | ||
470 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ | ||
471 | add r5, r3, r0; /* switch_thread returns the prev task */ | ||
472 | /* ( in the delay slot ) */ | ||
473 | brald r15, r20 /* fn was left in r20 */ | ||
474 | addk r5, r0, r19 /* ... and argument - in r19 */ | ||
475 | brid ret_from_trap | ||
476 | add r3, r0, r0 | ||
477 | |||
487 | C_ENTRY(sys_vfork): | 478 | C_ENTRY(sys_vfork): |
488 | brid microblaze_vfork /* Do real work (tail-call) */ | 479 | brid microblaze_vfork /* Do real work (tail-call) */ |
489 | addik r5, r1, 0 | 480 | addik r5, r1, 0 |
@@ -498,10 +489,6 @@ C_ENTRY(sys_clone): | |||
498 | brid do_fork /* Do real work (tail-call) */ | 489 | brid do_fork /* Do real work (tail-call) */ |
499 | add r8, r0, r0; /* Arg 3: (unused) */ | 490 | add r8, r0, r0; /* Arg 3: (unused) */ |
500 | 491 | ||
501 | C_ENTRY(sys_execve): | ||
502 | brid microblaze_execve; /* Do real work (tail-call).*/ | ||
503 | addik r8, r1, 0; /* add user context as 4th arg */ | ||
504 | |||
505 | C_ENTRY(sys_rt_sigreturn_wrapper): | 492 | C_ENTRY(sys_rt_sigreturn_wrapper): |
506 | brid sys_rt_sigreturn /* Do real work */ | 493 | brid sys_rt_sigreturn /* Do real work */ |
507 | addik r5, r1, 0; /* add user context as 1st arg */ | 494 | addik r5, r1, 0; /* add user context as 1st arg */ |
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 1944e00f07e1..29768c3dc358 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) */ |
@@ -246,6 +215,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp) | |||
246 | regs->pt_mode = 0; | 215 | regs->pt_mode = 0; |
247 | #ifdef CONFIG_MMU | 216 | #ifdef CONFIG_MMU |
248 | regs->msr |= MSR_UMS; | 217 | regs->msr |= MSR_UMS; |
218 | regs->msr &= ~MSR_VM; | ||
249 | #endif | 219 | #endif |
250 | } | 220 | } |
251 | 221 | ||
diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c index 404c0f24bd41..a6a7bae9f5c6 100644 --- a/arch/microblaze/kernel/sys_microblaze.c +++ b/arch/microblaze/kernel/sys_microblaze.c | |||
@@ -48,24 +48,6 @@ asmlinkage long microblaze_clone(int flags, unsigned long stack, | |||
48 | return do_fork(flags, stack, regs, 0, NULL, NULL); | 48 | return do_fork(flags, stack, regs, 0, NULL, NULL); |
49 | } | 49 | } |
50 | 50 | ||
51 | asmlinkage long microblaze_execve(const char __user *filenamei, | ||
52 | const char __user *const __user *argv, | ||
53 | const char __user *const __user *envp, | ||
54 | struct pt_regs *regs) | ||
55 | { | ||
56 | int error; | ||
57 | struct filename *filename; | ||
58 | |||
59 | filename = getname(filenamei); | ||
60 | error = PTR_ERR(filename); | ||
61 | if (IS_ERR(filename)) | ||
62 | goto out; | ||
63 | error = do_execve(filename->name, argv, envp, regs); | ||
64 | putname(filename); | ||
65 | out: | ||
66 | return error; | ||
67 | } | ||
68 | |||
69 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | 51 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, |
70 | unsigned long prot, unsigned long flags, | 52 | unsigned long prot, unsigned long flags, |
71 | unsigned long fd, off_t pgoff) | 53 | unsigned long fd, off_t pgoff) |
@@ -75,24 +57,3 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | |||
75 | 57 | ||
76 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); | 58 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); |
77 | } | 59 | } |
78 | |||
79 | /* | ||
80 | * Do a system call from kernel instead of calling sys_execve so we | ||
81 | * end up with proper pt_regs. | ||
82 | */ | ||
83 | int kernel_execve(const char *filename, | ||
84 | const char *const argv[], | ||
85 | const char *const envp[]) | ||
86 | { | ||
87 | register const char *__a __asm__("r5") = filename; | ||
88 | register const void *__b __asm__("r6") = argv; | ||
89 | register const void *__c __asm__("r7") = envp; | ||
90 | register unsigned long __syscall __asm__("r12") = __NR_execve; | ||
91 | register unsigned long __ret __asm__("r3"); | ||
92 | __asm__ __volatile__ ("brki r14, 0x8" | ||
93 | : "=r" (__ret), "=r" (__syscall) | ||
94 | : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c) | ||
95 | : "r4", "r8", "r9", | ||
96 | "r10", "r11", "r14", "cc", "memory"); | ||
97 | return __ret; | ||
98 | } | ||