aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig2
-rw-r--r--arch/mips/include/asm/processor.h2
-rw-r--r--arch/mips/include/asm/ptrace.h6
-rw-r--r--arch/mips/include/asm/unistd.h1
-rw-r--r--arch/mips/kernel/entry.S6
-rw-r--r--arch/mips/kernel/linux32.c21
-rw-r--r--arch/mips/kernel/mips_ksyms.c2
-rw-r--r--arch/mips/kernel/process.c62
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/scall64-o32.S2
-rw-r--r--arch/mips/kernel/syscall.c53
11 files changed, 39 insertions, 120 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index dba9390d37c..4183e62f178 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -40,6 +40,8 @@ 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
44 select GENERIC_KERNEL_EXECVE
43 45
44menu "Machine selection" 46menu "Machine selection"
45 47
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 5e33fabe354..d28c41e0887 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
313extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
314
315extern unsigned long thread_saved_pc(struct task_struct *tsk); 313extern unsigned long thread_saved_pc(struct task_struct *tsk);
316 314
317/* 315/*
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 4f5da948a77..cec5e125f7e 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -61,4 +61,10 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs)
61 die(str, regs); 61 die(str, regs);
62} 62}
63 63
64#define current_pt_regs() \
65({ \
66 unsigned long sp = (unsigned long)__builtin_frame_address(0); \
67 (struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1 - 32) - 1; \
68})
69
64#endif /* _ASM_PTRACE_H */ 70#endif /* _ASM_PTRACE_H */
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index 9e47cc11aa2..b306e2081ca 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -20,6 +20,7 @@
20#define __ARCH_OMIT_COMPAT_SYS_GETDENTS64 20#define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
21#define __ARCH_WANT_OLD_READDIR 21#define __ARCH_WANT_OLD_READDIR
22#define __ARCH_WANT_SYS_ALARM 22#define __ARCH_WANT_SYS_ALARM
23#define __ARCH_WANT_SYS_EXECVE
23#define __ARCH_WANT_SYS_GETHOSTNAME 24#define __ARCH_WANT_SYS_GETHOSTNAME
24#define __ARCH_WANT_SYS_IPC 25#define __ARCH_WANT_SYS_IPC
25#define __ARCH_WANT_SYS_PAUSE 26#define __ARCH_WANT_SYS_PAUSE
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index a6c13321200..3320cb4ac1d 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -65,6 +65,12 @@ need_resched:
65 b need_resched 65 b need_resched
66#endif 66#endif
67 67
68FEXPORT(ret_from_kernel_thread)
69 jal schedule_tail # a0 = struct task_struct *prev
70 move a0, s1
71 jal s0
72 j syscall_exit
73
68FEXPORT(ret_from_fork) 74FEXPORT(ret_from_fork)
69 jal schedule_tail # a0 = struct task_struct *prev 75 jal schedule_tail # a0 = struct task_struct *prev
70 76
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 3a21acedf88..8796dbc7e35 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -3,7 +3,6 @@
3 * 3 *
4 * Copyright (C) 2000 Silicon Graphics, Inc. 4 * Copyright (C) 2000 Silicon Graphics, Inc.
5 * Written by Ulf Carlsson (ulfc@engr.sgi.com) 5 * Written by Ulf Carlsson (ulfc@engr.sgi.com)
6 * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com)
7 */ 6 */
8#include <linux/compiler.h> 7#include <linux/compiler.h>
9#include <linux/mm.h> 8#include <linux/mm.h>
@@ -77,26 +76,6 @@ out:
77 return error; 76 return error;
78} 77}
79 78
80/*
81 * sys_execve() executes a new program.
82 */
83asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
84{
85 int error;
86 struct filename *filename;
87
88 filename = getname(compat_ptr(regs.regs[4]));
89 error = PTR_ERR(filename);
90 if (IS_ERR(filename))
91 goto out;
92 error = compat_do_execve(filename->name, compat_ptr(regs.regs[5]),
93 compat_ptr(regs.regs[6]), &regs);
94 putname(filename);
95
96out:
97 return error;
98}
99
100#define RLIM_INFINITY32 0x7fffffff 79#define RLIM_INFINITY32 0x7fffffff
101#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) 80#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
102 81
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 3fc1691110d..2d9304c2b54 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -32,8 +32,6 @@ EXPORT_SYMBOL(memset);
32EXPORT_SYMBOL(memcpy); 32EXPORT_SYMBOL(memcpy);
33EXPORT_SYMBOL(memmove); 33EXPORT_SYMBOL(memmove);
34 34
35EXPORT_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 e9a5fd7277f..d13720ac656 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
86asmlinkage void ret_from_fork(void); 86asmlinkage void ret_from_fork(void);
87asmlinkage void ret_from_kernel_thread(void);
87 88
88void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) 89void 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
115int copy_thread(unsigned long clone_flags, unsigned long usp, 116int 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 */
227static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *))
228{
229 do_exit(fn(arg));
230}
231
232long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
233{
234 struct pt_regs regs;
235
236 memset(&regs, 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, &regs, 0, NULL, NULL);
251}
252
253/*
254 * 236 *
255 */ 237 */
256struct mips_frame_info { 238struct mips_frame_info {
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index f6ba8381ee0..d27ca340d46 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -167,7 +167,7 @@ EXPORT(sysn32_call_table)
167 PTR sys_getsockopt 167 PTR sys_getsockopt
168 PTR sys_clone /* 6055 */ 168 PTR sys_clone /* 6055 */
169 PTR sys_fork 169 PTR sys_fork
170 PTR sys32_execve 170 PTR compat_sys_execve
171 PTR sys_exit 171 PTR sys_exit
172 PTR compat_sys_wait4 172 PTR compat_sys_wait4
173 PTR sys_kill /* 6060 */ 173 PTR sys_kill /* 6060 */
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 53c2d724576..9601be6afa3 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -203,7 +203,7 @@ sys_call_table:
203 PTR sys_creat 203 PTR sys_creat
204 PTR sys_link 204 PTR sys_link
205 PTR sys_unlink /* 4010 */ 205 PTR sys_unlink /* 4010 */
206 PTR sys32_execve 206 PTR compat_sys_execve
207 PTR sys_chdir 207 PTR sys_chdir
208 PTR compat_sys_time 208 PTR compat_sys_time
209 PTR sys_mknod 209 PTR sys_mknod
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 2bd561bc05a..c611e2df776 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -127,28 +127,6 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
127 parent_tidptr, child_tidptr); 127 parent_tidptr, child_tidptr);
128} 128}
129 129
130/*
131 * sys_execve() executes a new program.
132 */
133asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
134{
135 int error;
136 struct filename *filename;
137
138 filename = getname((const char __user *) (long)regs.regs[4]);
139 error = PTR_ERR(filename);
140 if (IS_ERR(filename))
141 goto out;
142 error = do_execve(filename->name,
143 (const char __user *const __user *) (long)regs.regs[5],
144 (const char __user *const __user *) (long)regs.regs[6],
145 &regs);
146 putname(filename);
147
148out:
149 return error;
150}
151
152SYSCALL_DEFINE1(set_thread_area, unsigned long, addr) 130SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
153{ 131{
154 struct thread_info *ti = task_thread_info(current); 132 struct thread_info *ti = task_thread_info(current);
@@ -313,34 +291,3 @@ asmlinkage void bad_stack(void)
313{ 291{
314 do_exit(SIGSEGV); 292 do_exit(SIGSEGV);
315} 293}
316
317/*
318 * Do a system call from kernel instead of calling sys_execve so we
319 * end up with proper pt_regs.
320 */
321int kernel_execve(const char *filename,
322 const char *const argv[],
323 const char *const envp[])
324{
325 register unsigned long __a0 asm("$4") = (unsigned long) filename;
326 register unsigned long __a1 asm("$5") = (unsigned long) argv;
327 register unsigned long __a2 asm("$6") = (unsigned long) envp;
328 register unsigned long __a3 asm("$7");
329 unsigned long __v0;
330
331 __asm__ volatile (" \n"
332 " .set noreorder \n"
333 " li $2, %5 # __NR_execve \n"
334 " syscall \n"
335 " move %0, $2 \n"
336 " .set reorder \n"
337 : "=&r" (__v0), "=r" (__a3)
338 : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
339 : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
340 "memory");
341
342 if (__a3 == 0)
343 return __v0;
344
345 return -__v0;
346}