aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r--arch/mips/kernel/traps.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index bf14da9f3e33..ae0c89d23ad7 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -56,6 +56,7 @@
56#include <asm/pgtable.h> 56#include <asm/pgtable.h>
57#include <asm/ptrace.h> 57#include <asm/ptrace.h>
58#include <asm/sections.h> 58#include <asm/sections.h>
59#include <asm/siginfo.h>
59#include <asm/tlbdebug.h> 60#include <asm/tlbdebug.h>
60#include <asm/traps.h> 61#include <asm/traps.h>
61#include <asm/uaccess.h> 62#include <asm/uaccess.h>
@@ -871,7 +872,7 @@ out:
871 exception_exit(prev_state); 872 exception_exit(prev_state);
872} 873}
873 874
874void do_trap_or_bp(struct pt_regs *regs, unsigned int code, 875void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code,
875 const char *str) 876 const char *str)
876{ 877{
877 siginfo_t info = { 0 }; 878 siginfo_t info = { 0 };
@@ -928,7 +929,13 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
928 default: 929 default:
929 scnprintf(b, sizeof(b), "%s instruction in kernel code", str); 930 scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
930 die_if_kernel(b, regs); 931 die_if_kernel(b, regs);
931 force_sig(SIGTRAP, current); 932 if (si_code) {
933 info.si_signo = SIGTRAP;
934 info.si_code = si_code;
935 force_sig_info(SIGTRAP, &info, current);
936 } else {
937 force_sig(SIGTRAP, current);
938 }
932 } 939 }
933} 940}
934 941
@@ -1012,7 +1019,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
1012 break; 1019 break;
1013 } 1020 }
1014 1021
1015 do_trap_or_bp(regs, bcode, "Break"); 1022 do_trap_or_bp(regs, bcode, TRAP_BRKPT, "Break");
1016 1023
1017out: 1024out:
1018 set_fs(seg); 1025 set_fs(seg);
@@ -1054,7 +1061,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
1054 tcode = (opcode >> 6) & ((1 << 10) - 1); 1061 tcode = (opcode >> 6) & ((1 << 10) - 1);
1055 } 1062 }
1056 1063
1057 do_trap_or_bp(regs, tcode, "Trap"); 1064 do_trap_or_bp(regs, tcode, 0, "Trap");
1058 1065
1059out: 1066out:
1060 set_fs(seg); 1067 set_fs(seg);
@@ -1115,19 +1122,7 @@ no_r2_instr:
1115 if (unlikely(compute_return_epc(regs) < 0)) 1122 if (unlikely(compute_return_epc(regs) < 0))
1116 goto out; 1123 goto out;
1117 1124
1118 if (get_isa16_mode(regs->cp0_epc)) { 1125 if (!get_isa16_mode(regs->cp0_epc)) {
1119 unsigned short mmop[2] = { 0 };
1120
1121 if (unlikely(get_user(mmop[0], (u16 __user *)epc + 0) < 0))
1122 status = SIGSEGV;
1123 if (unlikely(get_user(mmop[1], (u16 __user *)epc + 1) < 0))
1124 status = SIGSEGV;
1125 opcode = mmop[0];
1126 opcode = (opcode << 16) | mmop[1];
1127
1128 if (status < 0)
1129 status = simulate_rdhwr_mm(regs, opcode);
1130 } else {
1131 if (unlikely(get_user(opcode, epc) < 0)) 1126 if (unlikely(get_user(opcode, epc) < 0))
1132 status = SIGSEGV; 1127 status = SIGSEGV;
1133 1128
@@ -1142,6 +1137,18 @@ no_r2_instr:
1142 1137
1143 if (status < 0) 1138 if (status < 0)
1144 status = simulate_fp(regs, opcode, old_epc, old31); 1139 status = simulate_fp(regs, opcode, old_epc, old31);
1140 } else if (cpu_has_mmips) {
1141 unsigned short mmop[2] = { 0 };
1142
1143 if (unlikely(get_user(mmop[0], (u16 __user *)epc + 0) < 0))
1144 status = SIGSEGV;
1145 if (unlikely(get_user(mmop[1], (u16 __user *)epc + 1) < 0))
1146 status = SIGSEGV;
1147 opcode = mmop[0];
1148 opcode = (opcode << 16) | mmop[1];
1149
1150 if (status < 0)
1151 status = simulate_rdhwr_mm(regs, opcode);
1145 } 1152 }
1146 1153
1147 if (status < 0) 1154 if (status < 0)
@@ -1492,6 +1499,7 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
1492 */ 1499 */
1493asmlinkage void do_watch(struct pt_regs *regs) 1500asmlinkage void do_watch(struct pt_regs *regs)
1494{ 1501{
1502 siginfo_t info = { .si_signo = SIGTRAP, .si_code = TRAP_HWBKPT };
1495 enum ctx_state prev_state; 1503 enum ctx_state prev_state;
1496 u32 cause; 1504 u32 cause;
1497 1505
@@ -1512,7 +1520,7 @@ asmlinkage void do_watch(struct pt_regs *regs)
1512 if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) { 1520 if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) {
1513 mips_read_watch_registers(); 1521 mips_read_watch_registers();
1514 local_irq_enable(); 1522 local_irq_enable();
1515 force_sig(SIGTRAP, current); 1523 force_sig_info(SIGTRAP, &info, current);
1516 } else { 1524 } else {
1517 mips_clear_watch_registers(); 1525 mips_clear_watch_registers();
1518 local_irq_enable(); 1526 local_irq_enable();
@@ -2214,7 +2222,7 @@ void __init trap_init(void)
2214 2222
2215 /* 2223 /*
2216 * Copy the generic exception handlers to their final destination. 2224 * Copy the generic exception handlers to their final destination.
2217 * This will be overriden later as suitable for a particular 2225 * This will be overridden later as suitable for a particular
2218 * configuration. 2226 * configuration.
2219 */ 2227 */
2220 set_handler(0x180, &except_vec3_generic, 0x80); 2228 set_handler(0x180, &except_vec3_generic, 0x80);