aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/microblaze/kernel')
-rw-r--r--arch/microblaze/kernel/entry-nommu.S12
-rw-r--r--arch/microblaze/kernel/entry.S33
-rw-r--r--arch/microblaze/kernel/process.c72
-rw-r--r--arch/microblaze/kernel/sys_microblaze.c39
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
477ENTRY(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
477work_pending: 485work_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
562sys_execve:
563 brid microblaze_execve
564 addk r8, r1, r0
565
566sys_rt_sigreturn_wrapper: 570sys_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. */
3131:
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). */
480C_ENTRY(ret_from_fork): 462C_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
469C_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
487C_ENTRY(sys_vfork): 478C_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
501C_ENTRY(sys_execve):
502 brid microblaze_execve; /* Do real work (tail-call).*/
503 addik r8, r1, 0; /* add user context as 4th arg */
504
505C_ENTRY(sys_rt_sigreturn_wrapper): 492C_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
121int copy_thread(unsigned long clone_flags, unsigned long usp, 121int 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
212static void kernel_thread_helper(int (*fn)(void *), void *arg)
213{
214 fn(arg);
215 do_exit(-1);
216}
217
218int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
219{
220 struct pt_regs regs;
221
222 memset(&regs, 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 &regs, 0, NULL, NULL);
232}
233EXPORT_SYMBOL_GPL(kernel_thread);
234
235unsigned long get_wchan(struct task_struct *p) 204unsigned 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
51asmlinkage 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);
65out:
66 return error;
67}
68
69asmlinkage long sys_mmap(unsigned long addr, unsigned long len, 51asmlinkage 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 */
83int 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}