diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/mips/kernel/linux32.c | 27 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 5 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 5 | ||||
-rw-r--r-- | arch/mips/kernel/scall32-o32.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-64.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-n32.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/scall64-o32.S | 3 | ||||
-rw-r--r-- | arch/mips/kernel/syscall.c | 31 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 46 |
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 | |||
1472 | save_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, ®s, 0, | ||
1490 | parent_tidptr, child_tidptr); | ||
1491 | } | ||
1492 | |||
1493 | extern asmlinkage void sys_set_thread_area(u32 addr); | ||
1494 | asmlinkage 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, ®s, 0, | 202 | return do_fork(clone_flags, newsp, ®s, 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 | ||
263 | void 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 | |||
248 | asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) | 273 | asmlinkage 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 | */ | ||
507 | static 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 | |||
498 | asmlinkage void do_ov(struct pt_regs *regs) | 533 | asmlinkage 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: |