diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 46 |
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 | ||
874 | void do_trap_or_bp(struct pt_regs *regs, unsigned int code, | 875 | void 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 | ||
1017 | out: | 1024 | out: |
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 | ||
1059 | out: | 1066 | out: |
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 | */ |
1493 | asmlinkage void do_watch(struct pt_regs *regs) | 1500 | asmlinkage 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); |