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.c104
1 files changed, 76 insertions, 28 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index a75ae40184aa..0903d70b2cfe 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -13,6 +13,7 @@
13 */ 13 */
14#include <linux/bug.h> 14#include <linux/bug.h>
15#include <linux/compiler.h> 15#include <linux/compiler.h>
16#include <linux/context_tracking.h>
16#include <linux/kexec.h> 17#include <linux/kexec.h>
17#include <linux/init.h> 18#include <linux/init.h>
18#include <linux/kernel.h> 19#include <linux/kernel.h>
@@ -264,7 +265,7 @@ static void __show_regs(const struct pt_regs *regs)
264 265
265 printk("Status: %08x ", (uint32_t) regs->cp0_status); 266 printk("Status: %08x ", (uint32_t) regs->cp0_status);
266 267
267 if (current_cpu_data.isa_level == MIPS_CPU_ISA_I) { 268 if (cpu_has_3kex) {
268 if (regs->cp0_status & ST0_KUO) 269 if (regs->cp0_status & ST0_KUO)
269 printk("KUo "); 270 printk("KUo ");
270 if (regs->cp0_status & ST0_IEO) 271 if (regs->cp0_status & ST0_IEO)
@@ -277,7 +278,7 @@ static void __show_regs(const struct pt_regs *regs)
277 printk("KUc "); 278 printk("KUc ");
278 if (regs->cp0_status & ST0_IEC) 279 if (regs->cp0_status & ST0_IEC)
279 printk("IEc "); 280 printk("IEc ");
280 } else { 281 } else if (cpu_has_4kex) {
281 if (regs->cp0_status & ST0_KX) 282 if (regs->cp0_status & ST0_KX)
282 printk("KX "); 283 printk("KX ");
283 if (regs->cp0_status & ST0_SX) 284 if (regs->cp0_status & ST0_SX)
@@ -423,7 +424,9 @@ asmlinkage void do_be(struct pt_regs *regs)
423 const struct exception_table_entry *fixup = NULL; 424 const struct exception_table_entry *fixup = NULL;
424 int data = regs->cp0_cause & 4; 425 int data = regs->cp0_cause & 4;
425 int action = MIPS_BE_FATAL; 426 int action = MIPS_BE_FATAL;
427 enum ctx_state prev_state;
426 428
429 prev_state = exception_enter();
427 /* XXX For now. Fixme, this searches the wrong table ... */ 430 /* XXX For now. Fixme, this searches the wrong table ... */
428 if (data && !user_mode(regs)) 431 if (data && !user_mode(regs))
429 fixup = search_dbe_tables(exception_epc(regs)); 432 fixup = search_dbe_tables(exception_epc(regs));
@@ -436,11 +439,11 @@ asmlinkage void do_be(struct pt_regs *regs)
436 439
437 switch (action) { 440 switch (action) {
438 case MIPS_BE_DISCARD: 441 case MIPS_BE_DISCARD:
439 return; 442 goto out;
440 case MIPS_BE_FIXUP: 443 case MIPS_BE_FIXUP:
441 if (fixup) { 444 if (fixup) {
442 regs->cp0_epc = fixup->nextinsn; 445 regs->cp0_epc = fixup->nextinsn;
443 return; 446 goto out;
444 } 447 }
445 break; 448 break;
446 default: 449 default:
@@ -455,10 +458,13 @@ asmlinkage void do_be(struct pt_regs *regs)
455 field, regs->cp0_epc, field, regs->regs[31]); 458 field, regs->cp0_epc, field, regs->regs[31]);
456 if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), SIGBUS) 459 if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), SIGBUS)
457 == NOTIFY_STOP) 460 == NOTIFY_STOP)
458 return; 461 goto out;
459 462
460 die_if_kernel("Oops", regs); 463 die_if_kernel("Oops", regs);
461 force_sig(SIGBUS, current); 464 force_sig(SIGBUS, current);
465
466out:
467 exception_exit(prev_state);
462} 468}
463 469
464/* 470/*
@@ -673,8 +679,10 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
673 679
674asmlinkage void do_ov(struct pt_regs *regs) 680asmlinkage void do_ov(struct pt_regs *regs)
675{ 681{
682 enum ctx_state prev_state;
676 siginfo_t info; 683 siginfo_t info;
677 684
685 prev_state = exception_enter();
678 die_if_kernel("Integer overflow", regs); 686 die_if_kernel("Integer overflow", regs);
679 687
680 info.si_code = FPE_INTOVF; 688 info.si_code = FPE_INTOVF;
@@ -682,6 +690,7 @@ asmlinkage void do_ov(struct pt_regs *regs)
682 info.si_errno = 0; 690 info.si_errno = 0;
683 info.si_addr = (void __user *) regs->cp0_epc; 691 info.si_addr = (void __user *) regs->cp0_epc;
684 force_sig_info(SIGFPE, &info, current); 692 force_sig_info(SIGFPE, &info, current);
693 exception_exit(prev_state);
685} 694}
686 695
687int process_fpemu_return(int sig, void __user *fault_addr) 696int process_fpemu_return(int sig, void __user *fault_addr)
@@ -713,11 +722,13 @@ int process_fpemu_return(int sig, void __user *fault_addr)
713 */ 722 */
714asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) 723asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
715{ 724{
725 enum ctx_state prev_state;
716 siginfo_t info = {0}; 726 siginfo_t info = {0};
717 727
728 prev_state = exception_enter();
718 if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE) 729 if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE)
719 == NOTIFY_STOP) 730 == NOTIFY_STOP)
720 return; 731 goto out;
721 die_if_kernel("FP exception in kernel code", regs); 732 die_if_kernel("FP exception in kernel code", regs);
722 733
723 if (fcr31 & FPU_CSR_UNI_X) { 734 if (fcr31 & FPU_CSR_UNI_X) {
@@ -753,7 +764,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
753 /* If something went wrong, signal */ 764 /* If something went wrong, signal */
754 process_fpemu_return(sig, fault_addr); 765 process_fpemu_return(sig, fault_addr);
755 766
756 return; 767 goto out;
757 } else if (fcr31 & FPU_CSR_INV_X) 768 } else if (fcr31 & FPU_CSR_INV_X)
758 info.si_code = FPE_FLTINV; 769 info.si_code = FPE_FLTINV;
759 else if (fcr31 & FPU_CSR_DIV_X) 770 else if (fcr31 & FPU_CSR_DIV_X)
@@ -770,6 +781,9 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
770 info.si_errno = 0; 781 info.si_errno = 0;
771 info.si_addr = (void __user *) regs->cp0_epc; 782 info.si_addr = (void __user *) regs->cp0_epc;
772 force_sig_info(SIGFPE, &info, current); 783 force_sig_info(SIGFPE, &info, current);
784
785out:
786 exception_exit(prev_state);
773} 787}
774 788
775static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, 789static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
@@ -835,9 +849,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
835asmlinkage void do_bp(struct pt_regs *regs) 849asmlinkage void do_bp(struct pt_regs *regs)
836{ 850{
837 unsigned int opcode, bcode; 851 unsigned int opcode, bcode;
852 enum ctx_state prev_state;
838 unsigned long epc; 853 unsigned long epc;
839 u16 instr[2]; 854 u16 instr[2];
840 855
856 prev_state = exception_enter();
841 if (get_isa16_mode(regs->cp0_epc)) { 857 if (get_isa16_mode(regs->cp0_epc)) {
842 /* Calculate EPC. */ 858 /* Calculate EPC. */
843 epc = exception_epc(regs); 859 epc = exception_epc(regs);
@@ -852,7 +868,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
852 goto out_sigsegv; 868 goto out_sigsegv;
853 bcode = (instr[0] >> 6) & 0x3f; 869 bcode = (instr[0] >> 6) & 0x3f;
854 do_trap_or_bp(regs, bcode, "Break"); 870 do_trap_or_bp(regs, bcode, "Break");
855 return; 871 goto out;
856 } 872 }
857 } else { 873 } else {
858 if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) 874 if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
@@ -876,12 +892,12 @@ asmlinkage void do_bp(struct pt_regs *regs)
876 switch (bcode) { 892 switch (bcode) {
877 case BRK_KPROBE_BP: 893 case BRK_KPROBE_BP:
878 if (notify_die(DIE_BREAK, "debug", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) 894 if (notify_die(DIE_BREAK, "debug", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
879 return; 895 goto out;
880 else 896 else
881 break; 897 break;
882 case BRK_KPROBE_SSTEPBP: 898 case BRK_KPROBE_SSTEPBP:
883 if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) 899 if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
884 return; 900 goto out;
885 else 901 else
886 break; 902 break;
887 default: 903 default:
@@ -889,18 +905,24 @@ asmlinkage void do_bp(struct pt_regs *regs)
889 } 905 }
890 906
891 do_trap_or_bp(regs, bcode, "Break"); 907 do_trap_or_bp(regs, bcode, "Break");
908
909out:
910 exception_exit(prev_state);
892 return; 911 return;
893 912
894out_sigsegv: 913out_sigsegv:
895 force_sig(SIGSEGV, current); 914 force_sig(SIGSEGV, current);
915 goto out;
896} 916}
897 917
898asmlinkage void do_tr(struct pt_regs *regs) 918asmlinkage void do_tr(struct pt_regs *regs)
899{ 919{
900 u32 opcode, tcode = 0; 920 u32 opcode, tcode = 0;
921 enum ctx_state prev_state;
901 u16 instr[2]; 922 u16 instr[2];
902 unsigned long epc = msk_isa16_mode(exception_epc(regs)); 923 unsigned long epc = msk_isa16_mode(exception_epc(regs));
903 924
925 prev_state = exception_enter();
904 if (get_isa16_mode(regs->cp0_epc)) { 926 if (get_isa16_mode(regs->cp0_epc)) {
905 if (__get_user(instr[0], (u16 __user *)(epc + 0)) || 927 if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
906 __get_user(instr[1], (u16 __user *)(epc + 2))) 928 __get_user(instr[1], (u16 __user *)(epc + 2)))
@@ -918,10 +940,14 @@ asmlinkage void do_tr(struct pt_regs *regs)
918 } 940 }
919 941
920 do_trap_or_bp(regs, tcode, "Trap"); 942 do_trap_or_bp(regs, tcode, "Trap");
943
944out:
945 exception_exit(prev_state);
921 return; 946 return;
922 947
923out_sigsegv: 948out_sigsegv:
924 force_sig(SIGSEGV, current); 949 force_sig(SIGSEGV, current);
950 goto out;
925} 951}
926 952
927asmlinkage void do_ri(struct pt_regs *regs) 953asmlinkage void do_ri(struct pt_regs *regs)
@@ -929,17 +955,19 @@ asmlinkage void do_ri(struct pt_regs *regs)
929 unsigned int __user *epc = (unsigned int __user *)exception_epc(regs); 955 unsigned int __user *epc = (unsigned int __user *)exception_epc(regs);
930 unsigned long old_epc = regs->cp0_epc; 956 unsigned long old_epc = regs->cp0_epc;
931 unsigned long old31 = regs->regs[31]; 957 unsigned long old31 = regs->regs[31];
958 enum ctx_state prev_state;
932 unsigned int opcode = 0; 959 unsigned int opcode = 0;
933 int status = -1; 960 int status = -1;
934 961
962 prev_state = exception_enter();
935 if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), SIGILL) 963 if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), SIGILL)
936 == NOTIFY_STOP) 964 == NOTIFY_STOP)
937 return; 965 goto out;
938 966
939 die_if_kernel("Reserved instruction in kernel code", regs); 967 die_if_kernel("Reserved instruction in kernel code", regs);
940 968
941 if (unlikely(compute_return_epc(regs) < 0)) 969 if (unlikely(compute_return_epc(regs) < 0))
942 return; 970 goto out;
943 971
944 if (get_isa16_mode(regs->cp0_epc)) { 972 if (get_isa16_mode(regs->cp0_epc)) {
945 unsigned short mmop[2] = { 0 }; 973 unsigned short mmop[2] = { 0 };
@@ -974,6 +1002,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
974 regs->regs[31] = old31; 1002 regs->regs[31] = old31;
975 force_sig(status, current); 1003 force_sig(status, current);
976 } 1004 }
1005
1006out:
1007 exception_exit(prev_state);
977} 1008}
978 1009
979/* 1010/*
@@ -1025,21 +1056,16 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
1025{ 1056{
1026 struct pt_regs *regs = data; 1057 struct pt_regs *regs = data;
1027 1058
1028 switch (action) { 1059 die_if_kernel("COP2: Unhandled kernel unaligned access or invalid "
1029 default:
1030 die_if_kernel("Unhandled kernel unaligned access or invalid "
1031 "instruction", regs); 1060 "instruction", regs);
1032 /* Fall through */ 1061 force_sig(SIGILL, current);
1033
1034 case CU2_EXCEPTION:
1035 force_sig(SIGILL, current);
1036 }
1037 1062
1038 return NOTIFY_OK; 1063 return NOTIFY_OK;
1039} 1064}
1040 1065
1041asmlinkage void do_cpu(struct pt_regs *regs) 1066asmlinkage void do_cpu(struct pt_regs *regs)
1042{ 1067{
1068 enum ctx_state prev_state;
1043 unsigned int __user *epc; 1069 unsigned int __user *epc;
1044 unsigned long old_epc, old31; 1070 unsigned long old_epc, old31;
1045 unsigned int opcode; 1071 unsigned int opcode;
@@ -1047,10 +1073,12 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1047 int status; 1073 int status;
1048 unsigned long __maybe_unused flags; 1074 unsigned long __maybe_unused flags;
1049 1075
1050 die_if_kernel("do_cpu invoked from kernel context!", regs); 1076 prev_state = exception_enter();
1051
1052 cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; 1077 cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
1053 1078
1079 if (cpid != 2)
1080 die_if_kernel("do_cpu invoked from kernel context!", regs);
1081
1054 switch (cpid) { 1082 switch (cpid) {
1055 case 0: 1083 case 0:
1056 epc = (unsigned int __user *)exception_epc(regs); 1084 epc = (unsigned int __user *)exception_epc(regs);
@@ -1060,7 +1088,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1060 status = -1; 1088 status = -1;
1061 1089
1062 if (unlikely(compute_return_epc(regs) < 0)) 1090 if (unlikely(compute_return_epc(regs) < 0))
1063 return; 1091 goto out;
1064 1092
1065 if (get_isa16_mode(regs->cp0_epc)) { 1093 if (get_isa16_mode(regs->cp0_epc)) {
1066 unsigned short mmop[2] = { 0 }; 1094 unsigned short mmop[2] = { 0 };
@@ -1093,7 +1121,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1093 force_sig(status, current); 1121 force_sig(status, current);
1094 } 1122 }
1095 1123
1096 return; 1124 goto out;
1097 1125
1098 case 3: 1126 case 3:
1099 /* 1127 /*
@@ -1131,19 +1159,26 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1131 mt_ase_fp_affinity(); 1159 mt_ase_fp_affinity();
1132 } 1160 }
1133 1161
1134 return; 1162 goto out;
1135 1163
1136 case 2: 1164 case 2:
1137 raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); 1165 raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
1138 return; 1166 goto out;
1139 } 1167 }
1140 1168
1141 force_sig(SIGILL, current); 1169 force_sig(SIGILL, current);
1170
1171out:
1172 exception_exit(prev_state);
1142} 1173}
1143 1174
1144asmlinkage void do_mdmx(struct pt_regs *regs) 1175asmlinkage void do_mdmx(struct pt_regs *regs)
1145{ 1176{
1177 enum ctx_state prev_state;
1178
1179 prev_state = exception_enter();
1146 force_sig(SIGILL, current); 1180 force_sig(SIGILL, current);
1181 exception_exit(prev_state);
1147} 1182}
1148 1183
1149/* 1184/*
@@ -1151,8 +1186,10 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
1151 */ 1186 */
1152asmlinkage void do_watch(struct pt_regs *regs) 1187asmlinkage void do_watch(struct pt_regs *regs)
1153{ 1188{
1189 enum ctx_state prev_state;
1154 u32 cause; 1190 u32 cause;
1155 1191
1192 prev_state = exception_enter();
1156 /* 1193 /*
1157 * Clear WP (bit 22) bit of cause register so we don't loop 1194 * Clear WP (bit 22) bit of cause register so we don't loop
1158 * forever. 1195 * forever.
@@ -1174,13 +1211,16 @@ asmlinkage void do_watch(struct pt_regs *regs)
1174 mips_clear_watch_registers(); 1211 mips_clear_watch_registers();
1175 local_irq_enable(); 1212 local_irq_enable();
1176 } 1213 }
1214 exception_exit(prev_state);
1177} 1215}
1178 1216
1179asmlinkage void do_mcheck(struct pt_regs *regs) 1217asmlinkage void do_mcheck(struct pt_regs *regs)
1180{ 1218{
1181 const int field = 2 * sizeof(unsigned long); 1219 const int field = 2 * sizeof(unsigned long);
1182 int multi_match = regs->cp0_status & ST0_TS; 1220 int multi_match = regs->cp0_status & ST0_TS;
1221 enum ctx_state prev_state;
1183 1222
1223 prev_state = exception_enter();
1184 show_regs(regs); 1224 show_regs(regs);
1185 1225
1186 if (multi_match) { 1226 if (multi_match) {
@@ -1202,6 +1242,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
1202 panic("Caught Machine Check exception - %scaused by multiple " 1242 panic("Caught Machine Check exception - %scaused by multiple "
1203 "matching entries in the TLB.", 1243 "matching entries in the TLB.",
1204 (multi_match) ? "" : "not "); 1244 (multi_match) ? "" : "not ");
1245 exception_exit(prev_state);
1205} 1246}
1206 1247
1207asmlinkage void do_mt(struct pt_regs *regs) 1248asmlinkage void do_mt(struct pt_regs *regs)
@@ -1627,7 +1668,6 @@ void *set_vi_handler(int n, vi_handler_t addr)
1627} 1668}
1628 1669
1629extern void tlb_init(void); 1670extern void tlb_init(void);
1630extern void flush_tlb_handlers(void);
1631 1671
1632/* 1672/*
1633 * Timer interrupt 1673 * Timer interrupt
@@ -1837,6 +1877,15 @@ void __init trap_init(void)
1837 ebase += (read_c0_ebase() & 0x3ffff000); 1877 ebase += (read_c0_ebase() & 0x3ffff000);
1838 } 1878 }
1839 1879
1880 if (cpu_has_mmips) {
1881 unsigned int config3 = read_c0_config3();
1882
1883 if (IS_ENABLED(CONFIG_CPU_MICROMIPS))
1884 write_c0_config3(config3 | MIPS_CONF3_ISA_OE);
1885 else
1886 write_c0_config3(config3 & ~MIPS_CONF3_ISA_OE);
1887 }
1888
1840 if (board_ebase_setup) 1889 if (board_ebase_setup)
1841 board_ebase_setup(); 1890 board_ebase_setup();
1842 per_cpu_trap_init(true); 1891 per_cpu_trap_init(true);
@@ -1956,7 +2005,6 @@ void __init trap_init(void)
1956 set_handler(0x080, &except_vec3_generic, 0x80); 2005 set_handler(0x080, &except_vec3_generic, 0x80);
1957 2006
1958 local_flush_icache_range(ebase, ebase + 0x400); 2007 local_flush_icache_range(ebase, ebase + 0x400);
1959 flush_tlb_handlers();
1960 2008
1961 sort_extable(__start___dbe_table, __stop___dbe_table); 2009 sort_extable(__start___dbe_table, __stop___dbe_table);
1962 2010