diff options
Diffstat (limited to 'arch/score')
-rw-r--r-- | arch/score/Kconfig | 2 | ||||
-rw-r--r-- | arch/score/include/asm/processor.h | 1 | ||||
-rw-r--r-- | arch/score/include/asm/syscalls.h | 1 | ||||
-rw-r--r-- | arch/score/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/score/kernel/entry.S | 12 | ||||
-rw-r--r-- | arch/score/kernel/process.c | 55 | ||||
-rw-r--r-- | arch/score/kernel/signal.c | 7 | ||||
-rw-r--r-- | arch/score/kernel/sys_score.c | 54 |
8 files changed, 26 insertions, 107 deletions
diff --git a/arch/score/Kconfig b/arch/score/Kconfig index 4f93a431a45a..a285e78fb9c5 100644 --- a/arch/score/Kconfig +++ b/arch/score/Kconfig | |||
@@ -13,6 +13,8 @@ config SCORE | |||
13 | select GENERIC_CLOCKEVENTS | 13 | select GENERIC_CLOCKEVENTS |
14 | select HAVE_MOD_ARCH_SPECIFIC | 14 | select HAVE_MOD_ARCH_SPECIFIC |
15 | select MODULES_USE_ELF_REL | 15 | select MODULES_USE_ELF_REL |
16 | select GENERIC_KERNEL_THREAD | ||
17 | select GENERIC_KERNEL_EXECVE | ||
16 | 18 | ||
17 | choice | 19 | choice |
18 | prompt "System type" | 20 | prompt "System type" |
diff --git a/arch/score/include/asm/processor.h b/arch/score/include/asm/processor.h index ab3aceb54209..d9a922d8711b 100644 --- a/arch/score/include/asm/processor.h +++ b/arch/score/include/asm/processor.h | |||
@@ -13,7 +13,6 @@ struct task_struct; | |||
13 | */ | 13 | */ |
14 | extern void (*cpu_wait)(void); | 14 | extern void (*cpu_wait)(void); |
15 | 15 | ||
16 | extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
17 | extern unsigned long thread_saved_pc(struct task_struct *tsk); | 16 | extern unsigned long thread_saved_pc(struct task_struct *tsk); |
18 | extern void start_thread(struct pt_regs *regs, | 17 | extern void start_thread(struct pt_regs *regs, |
19 | unsigned long pc, unsigned long sp); | 18 | unsigned long pc, unsigned long sp); |
diff --git a/arch/score/include/asm/syscalls.h b/arch/score/include/asm/syscalls.h index 1dd5e0d6b0c3..8d332534342f 100644 --- a/arch/score/include/asm/syscalls.h +++ b/arch/score/include/asm/syscalls.h | |||
@@ -2,7 +2,6 @@ | |||
2 | #define _ASM_SCORE_SYSCALLS_H | 2 | #define _ASM_SCORE_SYSCALLS_H |
3 | 3 | ||
4 | asmlinkage long score_clone(struct pt_regs *regs); | 4 | asmlinkage long score_clone(struct pt_regs *regs); |
5 | asmlinkage long score_execve(struct pt_regs *regs); | ||
6 | asmlinkage long score_sigaltstack(struct pt_regs *regs); | 5 | asmlinkage long score_sigaltstack(struct pt_regs *regs); |
7 | asmlinkage long score_rt_sigreturn(struct pt_regs *regs); | 6 | asmlinkage long score_rt_sigreturn(struct pt_regs *regs); |
8 | 7 | ||
diff --git a/arch/score/include/asm/unistd.h b/arch/score/include/asm/unistd.h index a862384e9c16..b006ca435120 100644 --- a/arch/score/include/asm/unistd.h +++ b/arch/score/include/asm/unistd.h | |||
@@ -4,5 +4,6 @@ | |||
4 | #define __ARCH_WANT_SYSCALL_NO_FLAGS | 4 | #define __ARCH_WANT_SYSCALL_NO_FLAGS |
5 | #define __ARCH_WANT_SYSCALL_OFF_T | 5 | #define __ARCH_WANT_SYSCALL_OFF_T |
6 | #define __ARCH_WANT_SYSCALL_DEPRECATED | 6 | #define __ARCH_WANT_SYSCALL_DEPRECATED |
7 | #define __ARCH_WANT_SYS_EXECVE | ||
7 | 8 | ||
8 | #include <asm-generic/unistd.h> | 9 | #include <asm-generic/unistd.h> |
diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S index 83bb96079c43..da9901088bbb 100644 --- a/arch/score/kernel/entry.S +++ b/arch/score/kernel/entry.S | |||
@@ -278,6 +278,13 @@ need_resched: | |||
278 | nop | 278 | nop |
279 | #endif | 279 | #endif |
280 | 280 | ||
281 | ENTRY(ret_from_kernel_thread) | ||
282 | bl schedule_tail # r4=struct task_struct *prev | ||
283 | nop | ||
284 | mv r4, r13 | ||
285 | brl r12 | ||
286 | j syscall_exit | ||
287 | |||
281 | ENTRY(ret_from_fork) | 288 | ENTRY(ret_from_fork) |
282 | bl schedule_tail # r4=struct task_struct *prev | 289 | bl schedule_tail # r4=struct task_struct *prev |
283 | 290 | ||
@@ -480,11 +487,6 @@ illegal_syscall: | |||
480 | sw r9, [r0, PT_R7] | 487 | sw r9, [r0, PT_R7] |
481 | j syscall_return | 488 | j syscall_return |
482 | 489 | ||
483 | ENTRY(sys_execve) | ||
484 | mv r4, r0 | ||
485 | la r8, score_execve | ||
486 | br r8 | ||
487 | |||
488 | ENTRY(sys_clone) | 490 | ENTRY(sys_clone) |
489 | mv r4, r0 | 491 | mv r4, r0 |
490 | la r8, score_clone | 492 | la r8, score_clone |
diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index 637970cfd3f4..6f311cf64b99 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c | |||
@@ -60,6 +60,7 @@ void __noreturn cpu_idle(void) | |||
60 | } | 60 | } |
61 | 61 | ||
62 | void ret_from_fork(void); | 62 | void ret_from_fork(void); |
63 | void ret_from_kernel_thread(void); | ||
63 | 64 | ||
64 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) | 65 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) |
65 | { | 66 | { |
@@ -86,29 +87,27 @@ void flush_thread(void) {} | |||
86 | * set up the kernel stack and exception frames for a new process | 87 | * set up the kernel stack and exception frames for a new process |
87 | */ | 88 | */ |
88 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 89 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
89 | unsigned long unused, | 90 | unsigned long arg, |
90 | struct task_struct *p, struct pt_regs *regs) | 91 | struct task_struct *p, struct pt_regs *regs) |
91 | { | 92 | { |
92 | struct thread_info *ti = task_thread_info(p); | 93 | struct thread_info *ti = task_thread_info(p); |
93 | struct pt_regs *childregs = task_pt_regs(p); | 94 | struct pt_regs *childregs = task_pt_regs(p); |
94 | 95 | ||
95 | p->set_child_tid = NULL; | 96 | p->thread.reg0 = (unsigned long) childregs; |
96 | p->clear_child_tid = NULL; | 97 | if (unlikely(!regs)) { |
97 | 98 | memset(childregs, 0, sizeof(struct pt_regs)); | |
98 | *childregs = *regs; | 99 | p->thread->reg12 = usp; |
99 | childregs->regs[7] = 0; /* Clear error flag */ | 100 | p->thread->reg13 = arg; |
100 | childregs->regs[4] = 0; /* Child gets zero as return value */ | 101 | p->thread.reg3 = (unsigned long) ret_from_kernel_thread; |
101 | regs->regs[4] = p->pid; | ||
102 | |||
103 | if (childregs->cp0_psr & 0x8) { /* test kernel fork or user fork */ | ||
104 | childregs->regs[0] = usp; /* user fork */ | ||
105 | } else { | 102 | } else { |
106 | childregs->regs[28] = (unsigned long) ti; /* kernel fork */ | 103 | *childregs = *regs; |
107 | childregs->regs[0] = (unsigned long) childregs; | 104 | childregs->regs[7] = 0; /* Clear error flag */ |
105 | childregs->regs[4] = 0; /* Child gets zero as return value */ | ||
106 | childregs->regs[0] = usp; /* user fork */ | ||
107 | regs->regs[4] = p->pid; /* WTF? */ | ||
108 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
108 | } | 109 | } |
109 | 110 | ||
110 | p->thread.reg0 = (unsigned long) childregs; | ||
111 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
112 | p->thread.cp0_psr = 0; | 111 | p->thread.cp0_psr = 0; |
113 | 112 | ||
114 | return 0; | 113 | return 0; |
@@ -120,32 +119,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) | |||
120 | return 1; | 119 | return 1; |
121 | } | 120 | } |
122 | 121 | ||
123 | static void __noreturn | ||
124 | kernel_thread_helper(void *unused0, int (*fn)(void *), | ||
125 | void *arg, void *unused1) | ||
126 | { | ||
127 | do_exit(fn(arg)); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Create a kernel thread. | ||
132 | */ | ||
133 | long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
134 | { | ||
135 | struct pt_regs regs; | ||
136 | |||
137 | memset(®s, 0, sizeof(regs)); | ||
138 | |||
139 | regs.regs[6] = (unsigned long) arg; | ||
140 | regs.regs[5] = (unsigned long) fn; | ||
141 | regs.cp0_epc = (unsigned long) kernel_thread_helper; | ||
142 | regs.cp0_psr = (regs.cp0_psr & ~(0x1|0x4|0x8)) | \ | ||
143 | ((regs.cp0_psr & 0x3) << 2); | ||
144 | |||
145 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, \ | ||
146 | 0, ®s, 0, NULL, NULL); | ||
147 | } | ||
148 | |||
149 | unsigned long thread_saved_pc(struct task_struct *tsk) | 122 | unsigned long thread_saved_pc(struct task_struct *tsk) |
150 | { | 123 | { |
151 | return task_pt_regs(tsk)->cp0_epc; | 124 | return task_pt_regs(tsk)->cp0_epc; |
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index c268bbf8b410..02353bde92d8 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c | |||
@@ -148,7 +148,6 @@ score_rt_sigreturn(struct pt_regs *regs) | |||
148 | { | 148 | { |
149 | struct rt_sigframe __user *frame; | 149 | struct rt_sigframe __user *frame; |
150 | sigset_t set; | 150 | sigset_t set; |
151 | stack_t st; | ||
152 | int sig; | 151 | int sig; |
153 | 152 | ||
154 | /* Always make any pending restarted system calls return -EINTR */ | 153 | /* Always make any pending restarted system calls return -EINTR */ |
@@ -168,12 +167,10 @@ score_rt_sigreturn(struct pt_regs *regs) | |||
168 | else if (sig) | 167 | else if (sig) |
169 | force_sig(sig, current); | 168 | force_sig(sig, current); |
170 | 169 | ||
171 | if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) | ||
172 | goto badframe; | ||
173 | |||
174 | /* It is more difficult to avoid calling this function than to | 170 | /* It is more difficult to avoid calling this function than to |
175 | call it and ignore errors. */ | 171 | call it and ignore errors. */ |
176 | do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]); | 172 | if (do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs->regs[0]) == -EFAULT) |
173 | goto badframe; | ||
177 | regs->is_syscall = 0; | 174 | regs->is_syscall = 0; |
178 | 175 | ||
179 | __asm__ __volatile__( | 176 | __asm__ __volatile__( |
diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c index d45cf00a3351..c54434c2fd9d 100644 --- a/arch/score/kernel/sys_score.c +++ b/arch/score/kernel/sys_score.c | |||
@@ -83,57 +83,3 @@ score_vfork(struct pt_regs *regs) | |||
83 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, | 83 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, |
84 | regs->regs[0], regs, 0, NULL, NULL); | 84 | regs->regs[0], regs, 0, NULL, NULL); |
85 | } | 85 | } |
86 | |||
87 | /* | ||
88 | * sys_execve() executes a new program. | ||
89 | * This is called indirectly via a small wrapper | ||
90 | */ | ||
91 | asmlinkage long | ||
92 | score_execve(struct pt_regs *regs) | ||
93 | { | ||
94 | int error; | ||
95 | struct filename *filename; | ||
96 | |||
97 | filename = getname((char __user*)regs->regs[4]); | ||
98 | error = PTR_ERR(filename); | ||
99 | if (IS_ERR(filename)) | ||
100 | return error; | ||
101 | |||
102 | error = do_execve(filename->name, | ||
103 | (const char __user *const __user *)regs->regs[5], | ||
104 | (const char __user *const __user *)regs->regs[6], | ||
105 | regs); | ||
106 | |||
107 | putname(filename); | ||
108 | return error; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Do a system call from kernel instead of calling sys_execve so we | ||
113 | * end up with proper pt_regs. | ||
114 | */ | ||
115 | asmlinkage | ||
116 | int kernel_execve(const char *filename, | ||
117 | const char *const argv[], | ||
118 | const char *const envp[]) | ||
119 | { | ||
120 | register unsigned long __r4 asm("r4") = (unsigned long) filename; | ||
121 | register unsigned long __r5 asm("r5") = (unsigned long) argv; | ||
122 | register unsigned long __r6 asm("r6") = (unsigned long) envp; | ||
123 | register unsigned long __r7 asm("r7"); | ||
124 | |||
125 | __asm__ __volatile__ (" \n" | ||
126 | "ldi r27, %5 \n" | ||
127 | "syscall \n" | ||
128 | "mv %0, r4 \n" | ||
129 | "mv %1, r7 \n" | ||
130 | : "=&r" (__r4), "=r" (__r7) | ||
131 | : "r" (__r4), "r" (__r5), "r" (__r6), "i" (__NR_execve) | ||
132 | : "r8", "r9", "r10", "r11", "r22", "r23", "r24", "r25", | ||
133 | "r26", "r27", "memory"); | ||
134 | |||
135 | if (__r7 == 0) | ||
136 | return __r4; | ||
137 | |||
138 | return -__r4; | ||
139 | } | ||