aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/asm-offsets.c1
-rw-r--r--arch/mips/kernel/linux32.c27
-rw-r--r--arch/mips/kernel/process.c4
-rw-r--r--arch/mips/kernel/ptrace.c5
-rw-r--r--arch/mips/kernel/ptrace32.c5
-rw-r--r--arch/mips/kernel/scall32-o32.S1
-rw-r--r--arch/mips/kernel/scall64-64.S1
-rw-r--r--arch/mips/kernel/scall64-n32.S1
-rw-r--r--arch/mips/kernel/scall64-o32.S3
-rw-r--r--arch/mips/kernel/syscall.c31
-rw-r--r--arch/mips/kernel/traps.c46
11 files changed, 118 insertions, 7 deletions
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 2c11abb5a406..af69cdbdd50e 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -95,6 +95,7 @@ void output_thread_info_defines(void)
95 offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count); 95 offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count);
96 offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit); 96 offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit);
97 offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block); 97 offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block);
98 offset("#define TI_TP_VALUE ", struct thread_info, tp_value);
98 constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER); 99 constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER);
99 constant("#define _THREAD_SIZE ", THREAD_SIZE); 100 constant("#define _THREAD_SIZE ", THREAD_SIZE);
100 constant("#define _THREAD_MASK ", THREAD_MASK); 101 constant("#define _THREAD_MASK ", THREAD_MASK);
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index e8e886dd52d6..330cf84d21fe 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -1468,3 +1468,30 @@ sysn32_rt_sigtimedwait(const sigset_t __user *uthese,
1468 } 1468 }
1469 return sys_rt_sigtimedwait(uthese, uinfo, uts, sigsetsize); 1469 return sys_rt_sigtimedwait(uthese, uinfo, uts, sigsetsize);
1470} 1470}
1471
1472save_static_function(sys32_clone);
1473__attribute_used__ noinline static int
1474_sys32_clone(nabi_no_regargs struct pt_regs regs)
1475{
1476 unsigned long clone_flags;
1477 unsigned long newsp;
1478 int __user *parent_tidptr, *child_tidptr;
1479
1480 clone_flags = regs.regs[4];
1481 newsp = regs.regs[5];
1482 if (!newsp)
1483 newsp = regs.regs[29];
1484 parent_tidptr = (int *) regs.regs[6];
1485
1486 /* Use __dummy4 instead of getting it off the stack, so that
1487 syscall() works. */
1488 child_tidptr = (int __user *) __dummy4;
1489 return do_fork(clone_flags, newsp, &regs, 0,
1490 parent_tidptr, child_tidptr);
1491}
1492
1493extern asmlinkage void sys_set_thread_area(u32 addr);
1494asmlinkage void sys32_set_thread_area(u32 addr)
1495{
1496 sys_set_thread_area(AA(addr));
1497}
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 2b7a44deb856..368526af5f5e 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -89,6 +89,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
89 struct thread_info *ti = p->thread_info; 89 struct thread_info *ti = p->thread_info;
90 struct pt_regs *childregs; 90 struct pt_regs *childregs;
91 long childksp; 91 long childksp;
92 p->set_child_tid = p->clear_child_tid = NULL;
92 93
93 childksp = (unsigned long)ti + THREAD_SIZE - 32; 94 childksp = (unsigned long)ti + THREAD_SIZE - 32;
94 95
@@ -134,6 +135,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
134 childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); 135 childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
135 clear_tsk_thread_flag(p, TIF_USEDFPU); 136 clear_tsk_thread_flag(p, TIF_USEDFPU);
136 137
138 if (clone_flags & CLONE_SETTLS)
139 ti->tp_value = regs->regs[7];
140
137 return 0; 141 return 0;
138} 142}
139 143
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 2c7fc7472fb2..649c90dee38e 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -289,6 +289,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
289 ret = ptrace_detach(child, data); 289 ret = ptrace_detach(child, data);
290 break; 290 break;
291 291
292 case PTRACE_GET_THREAD_AREA:
293 ret = put_user(child->thread_info->tp_value,
294 (unsigned long __user *) data);
295 break;
296
292 default: 297 default:
293 ret = ptrace_request(child, request, addr, data); 298 ret = ptrace_request(child, request, addr, data);
294 break; 299 break;
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index a8a72c9a1cca..eb446e525908 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -268,6 +268,11 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
268 wake_up_process(child); 268 wake_up_process(child);
269 break; 269 break;
270 270
271 case PTRACE_GET_THREAD_AREA:
272 ret = put_user(child->thread_info->tp_value,
273 (unsigned int __user *) (unsigned long) data);
274 break;
275
271 case PTRACE_DETACH: /* detach a process that was attached. */ 276 case PTRACE_DETACH: /* detach a process that was attached. */
272 ret = ptrace_detach(child, data); 277 ret = ptrace_detach(child, data);
273 break; 278 break;
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 9c4bb917d476..6fa1112512c8 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -623,6 +623,7 @@ einval: li v0, -EINVAL
623 sys sys_add_key 5 623 sys sys_add_key 5
624 sys sys_request_key 4 624 sys sys_request_key 4
625 sys sys_keyctl 5 625 sys sys_keyctl 5
626 sys sys_set_thread_area 1
626 627
627 .endm 628 .endm
628 629
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index ffb22a2068bf..d11f99b0ae53 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -449,3 +449,4 @@ sys_call_table:
449 PTR sys_add_key 449 PTR sys_add_key
450 PTR sys_request_key /* 5240 */ 450 PTR sys_request_key /* 5240 */
451 PTR sys_keyctl 451 PTR sys_keyctl
452 PTR sys_set_thread_area
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index d912218259e5..ce030412efbe 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -363,3 +363,4 @@ EXPORT(sysn32_call_table)
363 PTR sys_add_key 363 PTR sys_add_key
364 PTR sys_request_key 364 PTR sys_request_key
365 PTR sys_keyctl /* 6245 */ 365 PTR sys_keyctl /* 6245 */
366 PTR sys_set_thread_area
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 1017176bdce9..f49182ea73f8 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -322,7 +322,7 @@ sys_call_table:
322 PTR sys32_ipc 322 PTR sys32_ipc
323 PTR sys_fsync 323 PTR sys_fsync
324 PTR sys32_sigreturn 324 PTR sys32_sigreturn
325 PTR sys_clone /* 4120 */ 325 PTR sys32_clone /* 4120 */
326 PTR sys_setdomainname 326 PTR sys_setdomainname
327 PTR sys32_newuname 327 PTR sys32_newuname
328 PTR sys_ni_syscall /* sys_modify_ldt */ 328 PTR sys_ni_syscall /* sys_modify_ldt */
@@ -485,4 +485,5 @@ sys_call_table:
485 PTR sys_add_key /* 4280 */ 485 PTR sys_add_key /* 4280 */
486 PTR sys_request_key 486 PTR sys_request_key
487 PTR sys_keyctl 487 PTR sys_keyctl
488 PTR sys_set_thread_area
488 .size sys_call_table,.-sys_call_table 489 .size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 8fde242596f9..ee98eeb65e85 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -7,6 +7,7 @@
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2001 MIPS Technologies, Inc. 8 * Copyright (C) 2001 MIPS Technologies, Inc.
9 */ 9 */
10#include <linux/config.h>
10#include <linux/a.out.h> 11#include <linux/a.out.h>
11#include <linux/errno.h> 12#include <linux/errno.h>
12#include <linux/linkage.h> 13#include <linux/linkage.h>
@@ -176,14 +177,28 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
176{ 177{
177 unsigned long clone_flags; 178 unsigned long clone_flags;
178 unsigned long newsp; 179 unsigned long newsp;
179 int *parent_tidptr, *child_tidptr; 180 int __user *parent_tidptr, *child_tidptr;
180 181
181 clone_flags = regs.regs[4]; 182 clone_flags = regs.regs[4];
182 newsp = regs.regs[5]; 183 newsp = regs.regs[5];
183 if (!newsp) 184 if (!newsp)
184 newsp = regs.regs[29]; 185 newsp = regs.regs[29];
185 parent_tidptr = (int *) regs.regs[6]; 186 parent_tidptr = (int __user *) regs.regs[6];
186 child_tidptr = (int *) regs.regs[7]; 187#ifdef CONFIG_32BIT
188 /* We need to fetch the fifth argument off the stack. */
189 child_tidptr = NULL;
190 if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
191 int __user *__user *usp = (int __user *__user *) regs.regs[29];
192 if (regs.regs[2] == __NR_syscall) {
193 if (get_user (child_tidptr, &usp[5]))
194 return -EFAULT;
195 }
196 else if (get_user (child_tidptr, &usp[4]))
197 return -EFAULT;
198 }
199#else
200 child_tidptr = (int __user *) regs.regs[8];
201#endif
187 return do_fork(clone_flags, newsp, &regs, 0, 202 return do_fork(clone_flags, newsp, &regs, 0,
188 parent_tidptr, child_tidptr); 203 parent_tidptr, child_tidptr);
189} 204}
@@ -245,6 +260,16 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
245 return error; 260 return error;
246} 261}
247 262
263void sys_set_thread_area(unsigned long addr)
264{
265 struct thread_info *ti = current->thread_info;
266
267 ti->tp_value = addr;
268
269 /* If some future MIPS implementation has this register in hardware,
270 * we will need to update it here (and in context switches). */
271}
272
248asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) 273asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
249{ 274{
250 int tmp, len; 275 int tmp, len;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 94d9141c04c1..15fed0202154 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -360,6 +360,10 @@ static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
360#define OFFSET 0x0000ffff 360#define OFFSET 0x0000ffff
361#define LL 0xc0000000 361#define LL 0xc0000000
362#define SC 0xe0000000 362#define SC 0xe0000000
363#define SPEC3 0x7c000000
364#define RD 0x0000f800
365#define FUNC 0x0000003f
366#define RDHWR 0x0000003b
363 367
364/* 368/*
365 * The ll_bit is cleared by r*_switch.S 369 * The ll_bit is cleared by r*_switch.S
@@ -495,6 +499,37 @@ static inline int simulate_llsc(struct pt_regs *regs)
495 return -EFAULT; /* Strange things going on ... */ 499 return -EFAULT; /* Strange things going on ... */
496} 500}
497 501
502/*
503 * Simulate trapping 'rdhwr' instructions to provide user accessible
504 * registers not implemented in hardware. The only current use of this
505 * is the thread area pointer.
506 */
507static inline int simulate_rdhwr(struct pt_regs *regs)
508{
509 struct thread_info *ti = current->thread_info;
510 unsigned int opcode;
511
512 if (unlikely(get_insn_opcode(regs, &opcode)))
513 return -EFAULT;
514
515 if (unlikely(compute_return_epc(regs)))
516 return -EFAULT;
517
518 if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) {
519 int rd = (opcode & RD) >> 11;
520 int rt = (opcode & RT) >> 16;
521 switch (rd) {
522 case 29:
523 regs->regs[rt] = ti->tp_value;
524 break;
525 default:
526 return -EFAULT;
527 }
528 }
529
530 return 0;
531}
532
498asmlinkage void do_ov(struct pt_regs *regs) 533asmlinkage void do_ov(struct pt_regs *regs)
499{ 534{
500 siginfo_t info; 535 siginfo_t info;
@@ -641,6 +676,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
641 if (!simulate_llsc(regs)) 676 if (!simulate_llsc(regs))
642 return; 677 return;
643 678
679 if (!simulate_rdhwr(regs))
680 return;
681
644 force_sig(SIGILL, current); 682 force_sig(SIGILL, current);
645} 683}
646 684
@@ -654,11 +692,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
654 692
655 switch (cpid) { 693 switch (cpid) {
656 case 0: 694 case 0:
657 if (cpu_has_llsc) 695 if (!cpu_has_llsc)
658 break; 696 if (!simulate_llsc(regs))
697 return;
659 698
660 if (!simulate_llsc(regs)) 699 if (!simulate_rdhwr(regs))
661 return; 700 return;
701
662 break; 702 break;
663 703
664 case 1: 704 case 1: