diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 318 |
1 files changed, 226 insertions, 92 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 25225515451f..77cff1f6d050 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -8,8 +8,8 @@ | |||
8 | * Copyright (C) 1998 Ulf Carlsson | 8 | * Copyright (C) 1998 Ulf Carlsson |
9 | * Copyright (C) 1999 Silicon Graphics, Inc. | 9 | * Copyright (C) 1999 Silicon Graphics, Inc. |
10 | * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com | 10 | * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com |
11 | * Copyright (C) 2000, 01 MIPS Technologies, Inc. | ||
12 | * Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki | 11 | * Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki |
12 | * Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc. All rights reserved. | ||
13 | */ | 13 | */ |
14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
15 | #include <linux/compiler.h> | 15 | #include <linux/compiler.h> |
@@ -60,9 +60,9 @@ extern void check_wait(void); | |||
60 | extern asmlinkage void r4k_wait(void); | 60 | extern asmlinkage void r4k_wait(void); |
61 | extern asmlinkage void rollback_handle_int(void); | 61 | extern asmlinkage void rollback_handle_int(void); |
62 | extern asmlinkage void handle_int(void); | 62 | extern asmlinkage void handle_int(void); |
63 | extern asmlinkage void handle_tlbm(void); | 63 | extern u32 handle_tlbl[]; |
64 | extern asmlinkage void handle_tlbl(void); | 64 | extern u32 handle_tlbs[]; |
65 | extern asmlinkage void handle_tlbs(void); | 65 | extern u32 handle_tlbm[]; |
66 | extern asmlinkage void handle_adel(void); | 66 | extern asmlinkage void handle_adel(void); |
67 | extern asmlinkage void handle_ades(void); | 67 | extern asmlinkage void handle_ades(void); |
68 | extern asmlinkage void handle_ibe(void); | 68 | extern asmlinkage void handle_ibe(void); |
@@ -83,10 +83,6 @@ extern asmlinkage void handle_dsp(void); | |||
83 | extern asmlinkage void handle_mcheck(void); | 83 | extern asmlinkage void handle_mcheck(void); |
84 | extern asmlinkage void handle_reserved(void); | 84 | extern asmlinkage void handle_reserved(void); |
85 | 85 | ||
86 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, | ||
87 | struct mips_fpu_struct *ctx, int has_fpu, | ||
88 | void *__user *fault_addr); | ||
89 | |||
90 | void (*board_be_init)(void); | 86 | void (*board_be_init)(void); |
91 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); | 87 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); |
92 | void (*board_nmi_handler_setup)(void); | 88 | void (*board_nmi_handler_setup)(void); |
@@ -482,6 +478,12 @@ asmlinkage void do_be(struct pt_regs *regs) | |||
482 | #define SYNC 0x0000000f | 478 | #define SYNC 0x0000000f |
483 | #define RDHWR 0x0000003b | 479 | #define RDHWR 0x0000003b |
484 | 480 | ||
481 | /* microMIPS definitions */ | ||
482 | #define MM_POOL32A_FUNC 0xfc00ffff | ||
483 | #define MM_RDHWR 0x00006b3c | ||
484 | #define MM_RS 0x001f0000 | ||
485 | #define MM_RT 0x03e00000 | ||
486 | |||
485 | /* | 487 | /* |
486 | * The ll_bit is cleared by r*_switch.S | 488 | * The ll_bit is cleared by r*_switch.S |
487 | */ | 489 | */ |
@@ -596,42 +598,62 @@ static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) | |||
596 | * Simulate trapping 'rdhwr' instructions to provide user accessible | 598 | * Simulate trapping 'rdhwr' instructions to provide user accessible |
597 | * registers not implemented in hardware. | 599 | * registers not implemented in hardware. |
598 | */ | 600 | */ |
599 | static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) | 601 | static int simulate_rdhwr(struct pt_regs *regs, int rd, int rt) |
600 | { | 602 | { |
601 | struct thread_info *ti = task_thread_info(current); | 603 | struct thread_info *ti = task_thread_info(current); |
602 | 604 | ||
605 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
606 | 1, regs, 0); | ||
607 | switch (rd) { | ||
608 | case 0: /* CPU number */ | ||
609 | regs->regs[rt] = smp_processor_id(); | ||
610 | return 0; | ||
611 | case 1: /* SYNCI length */ | ||
612 | regs->regs[rt] = min(current_cpu_data.dcache.linesz, | ||
613 | current_cpu_data.icache.linesz); | ||
614 | return 0; | ||
615 | case 2: /* Read count register */ | ||
616 | regs->regs[rt] = read_c0_count(); | ||
617 | return 0; | ||
618 | case 3: /* Count register resolution */ | ||
619 | switch (current_cpu_data.cputype) { | ||
620 | case CPU_20KC: | ||
621 | case CPU_25KF: | ||
622 | regs->regs[rt] = 1; | ||
623 | break; | ||
624 | default: | ||
625 | regs->regs[rt] = 2; | ||
626 | } | ||
627 | return 0; | ||
628 | case 29: | ||
629 | regs->regs[rt] = ti->tp_value; | ||
630 | return 0; | ||
631 | default: | ||
632 | return -1; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | static int simulate_rdhwr_normal(struct pt_regs *regs, unsigned int opcode) | ||
637 | { | ||
603 | if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { | 638 | if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { |
604 | int rd = (opcode & RD) >> 11; | 639 | int rd = (opcode & RD) >> 11; |
605 | int rt = (opcode & RT) >> 16; | 640 | int rt = (opcode & RT) >> 16; |
606 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | 641 | |
607 | 1, regs, 0); | 642 | simulate_rdhwr(regs, rd, rt); |
608 | switch (rd) { | 643 | return 0; |
609 | case 0: /* CPU number */ | 644 | } |
610 | regs->regs[rt] = smp_processor_id(); | 645 | |
611 | return 0; | 646 | /* Not ours. */ |
612 | case 1: /* SYNCI length */ | 647 | return -1; |
613 | regs->regs[rt] = min(current_cpu_data.dcache.linesz, | 648 | } |
614 | current_cpu_data.icache.linesz); | 649 | |
615 | return 0; | 650 | static int simulate_rdhwr_mm(struct pt_regs *regs, unsigned short opcode) |
616 | case 2: /* Read count register */ | 651 | { |
617 | regs->regs[rt] = read_c0_count(); | 652 | if ((opcode & MM_POOL32A_FUNC) == MM_RDHWR) { |
618 | return 0; | 653 | int rd = (opcode & MM_RS) >> 16; |
619 | case 3: /* Count register resolution */ | 654 | int rt = (opcode & MM_RT) >> 21; |
620 | switch (current_cpu_data.cputype) { | 655 | simulate_rdhwr(regs, rd, rt); |
621 | case CPU_20KC: | 656 | return 0; |
622 | case CPU_25KF: | ||
623 | regs->regs[rt] = 1; | ||
624 | break; | ||
625 | default: | ||
626 | regs->regs[rt] = 2; | ||
627 | } | ||
628 | return 0; | ||
629 | case 29: | ||
630 | regs->regs[rt] = ti->tp_value; | ||
631 | return 0; | ||
632 | default: | ||
633 | return -1; | ||
634 | } | ||
635 | } | 657 | } |
636 | 658 | ||
637 | /* Not ours. */ | 659 | /* Not ours. */ |
@@ -662,7 +684,7 @@ asmlinkage void do_ov(struct pt_regs *regs) | |||
662 | force_sig_info(SIGFPE, &info, current); | 684 | force_sig_info(SIGFPE, &info, current); |
663 | } | 685 | } |
664 | 686 | ||
665 | static int process_fpemu_return(int sig, void __user *fault_addr) | 687 | int process_fpemu_return(int sig, void __user *fault_addr) |
666 | { | 688 | { |
667 | if (sig == SIGSEGV || sig == SIGBUS) { | 689 | if (sig == SIGSEGV || sig == SIGBUS) { |
668 | struct siginfo si = {0}; | 690 | struct siginfo si = {0}; |
@@ -813,9 +835,29 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, | |||
813 | asmlinkage void do_bp(struct pt_regs *regs) | 835 | asmlinkage void do_bp(struct pt_regs *regs) |
814 | { | 836 | { |
815 | unsigned int opcode, bcode; | 837 | unsigned int opcode, bcode; |
816 | 838 | unsigned long epc; | |
817 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | 839 | u16 instr[2]; |
818 | goto out_sigsegv; | 840 | |
841 | if (get_isa16_mode(regs->cp0_epc)) { | ||
842 | /* Calculate EPC. */ | ||
843 | epc = exception_epc(regs); | ||
844 | if (cpu_has_mmips) { | ||
845 | if ((__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc)) || | ||
846 | (__get_user(instr[1], (u16 __user *)msk_isa16_mode(epc + 2))))) | ||
847 | goto out_sigsegv; | ||
848 | opcode = (instr[0] << 16) | instr[1]; | ||
849 | } else { | ||
850 | /* MIPS16e mode */ | ||
851 | if (__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc))) | ||
852 | goto out_sigsegv; | ||
853 | bcode = (instr[0] >> 6) & 0x3f; | ||
854 | do_trap_or_bp(regs, bcode, "Break"); | ||
855 | return; | ||
856 | } | ||
857 | } else { | ||
858 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | ||
859 | goto out_sigsegv; | ||
860 | } | ||
819 | 861 | ||
820 | /* | 862 | /* |
821 | * There is the ancient bug in the MIPS assemblers that the break | 863 | * There is the ancient bug in the MIPS assemblers that the break |
@@ -856,13 +898,22 @@ out_sigsegv: | |||
856 | asmlinkage void do_tr(struct pt_regs *regs) | 898 | asmlinkage void do_tr(struct pt_regs *regs) |
857 | { | 899 | { |
858 | unsigned int opcode, tcode = 0; | 900 | unsigned int opcode, tcode = 0; |
901 | u16 instr[2]; | ||
902 | unsigned long epc = exception_epc(regs); | ||
859 | 903 | ||
860 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | 904 | if ((__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc))) || |
861 | goto out_sigsegv; | 905 | (__get_user(instr[1], (u16 __user *)msk_isa16_mode(epc + 2)))) |
906 | goto out_sigsegv; | ||
907 | opcode = (instr[0] << 16) | instr[1]; | ||
862 | 908 | ||
863 | /* Immediate versions don't provide a code. */ | 909 | /* Immediate versions don't provide a code. */ |
864 | if (!(opcode & OPCODE)) | 910 | if (!(opcode & OPCODE)) { |
865 | tcode = ((opcode >> 6) & ((1 << 10) - 1)); | 911 | if (get_isa16_mode(regs->cp0_epc)) |
912 | /* microMIPS */ | ||
913 | tcode = (opcode >> 12) & 0x1f; | ||
914 | else | ||
915 | tcode = ((opcode >> 6) & ((1 << 10) - 1)); | ||
916 | } | ||
866 | 917 | ||
867 | do_trap_or_bp(regs, tcode, "Trap"); | 918 | do_trap_or_bp(regs, tcode, "Trap"); |
868 | return; | 919 | return; |
@@ -875,6 +926,7 @@ asmlinkage void do_ri(struct pt_regs *regs) | |||
875 | { | 926 | { |
876 | unsigned int __user *epc = (unsigned int __user *)exception_epc(regs); | 927 | unsigned int __user *epc = (unsigned int __user *)exception_epc(regs); |
877 | unsigned long old_epc = regs->cp0_epc; | 928 | unsigned long old_epc = regs->cp0_epc; |
929 | unsigned long old31 = regs->regs[31]; | ||
878 | unsigned int opcode = 0; | 930 | unsigned int opcode = 0; |
879 | int status = -1; | 931 | int status = -1; |
880 | 932 | ||
@@ -887,23 +939,37 @@ asmlinkage void do_ri(struct pt_regs *regs) | |||
887 | if (unlikely(compute_return_epc(regs) < 0)) | 939 | if (unlikely(compute_return_epc(regs) < 0)) |
888 | return; | 940 | return; |
889 | 941 | ||
890 | if (unlikely(get_user(opcode, epc) < 0)) | 942 | if (get_isa16_mode(regs->cp0_epc)) { |
891 | status = SIGSEGV; | 943 | unsigned short mmop[2] = { 0 }; |
892 | 944 | ||
893 | if (!cpu_has_llsc && status < 0) | 945 | if (unlikely(get_user(mmop[0], epc) < 0)) |
894 | status = simulate_llsc(regs, opcode); | 946 | status = SIGSEGV; |
947 | if (unlikely(get_user(mmop[1], epc) < 0)) | ||
948 | status = SIGSEGV; | ||
949 | opcode = (mmop[0] << 16) | mmop[1]; | ||
895 | 950 | ||
896 | if (status < 0) | 951 | if (status < 0) |
897 | status = simulate_rdhwr(regs, opcode); | 952 | status = simulate_rdhwr_mm(regs, opcode); |
953 | } else { | ||
954 | if (unlikely(get_user(opcode, epc) < 0)) | ||
955 | status = SIGSEGV; | ||
898 | 956 | ||
899 | if (status < 0) | 957 | if (!cpu_has_llsc && status < 0) |
900 | status = simulate_sync(regs, opcode); | 958 | status = simulate_llsc(regs, opcode); |
959 | |||
960 | if (status < 0) | ||
961 | status = simulate_rdhwr_normal(regs, opcode); | ||
962 | |||
963 | if (status < 0) | ||
964 | status = simulate_sync(regs, opcode); | ||
965 | } | ||
901 | 966 | ||
902 | if (status < 0) | 967 | if (status < 0) |
903 | status = SIGILL; | 968 | status = SIGILL; |
904 | 969 | ||
905 | if (unlikely(status > 0)) { | 970 | if (unlikely(status > 0)) { |
906 | regs->cp0_epc = old_epc; /* Undo skip-over. */ | 971 | regs->cp0_epc = old_epc; /* Undo skip-over. */ |
972 | regs->regs[31] = old31; | ||
907 | force_sig(status, current); | 973 | force_sig(status, current); |
908 | } | 974 | } |
909 | } | 975 | } |
@@ -973,7 +1039,7 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action, | |||
973 | asmlinkage void do_cpu(struct pt_regs *regs) | 1039 | asmlinkage void do_cpu(struct pt_regs *regs) |
974 | { | 1040 | { |
975 | unsigned int __user *epc; | 1041 | unsigned int __user *epc; |
976 | unsigned long old_epc; | 1042 | unsigned long old_epc, old31; |
977 | unsigned int opcode; | 1043 | unsigned int opcode; |
978 | unsigned int cpid; | 1044 | unsigned int cpid; |
979 | int status; | 1045 | int status; |
@@ -987,26 +1053,41 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
987 | case 0: | 1053 | case 0: |
988 | epc = (unsigned int __user *)exception_epc(regs); | 1054 | epc = (unsigned int __user *)exception_epc(regs); |
989 | old_epc = regs->cp0_epc; | 1055 | old_epc = regs->cp0_epc; |
1056 | old31 = regs->regs[31]; | ||
990 | opcode = 0; | 1057 | opcode = 0; |
991 | status = -1; | 1058 | status = -1; |
992 | 1059 | ||
993 | if (unlikely(compute_return_epc(regs) < 0)) | 1060 | if (unlikely(compute_return_epc(regs) < 0)) |
994 | return; | 1061 | return; |
995 | 1062 | ||
996 | if (unlikely(get_user(opcode, epc) < 0)) | 1063 | if (get_isa16_mode(regs->cp0_epc)) { |
997 | status = SIGSEGV; | 1064 | unsigned short mmop[2] = { 0 }; |
998 | 1065 | ||
999 | if (!cpu_has_llsc && status < 0) | 1066 | if (unlikely(get_user(mmop[0], epc) < 0)) |
1000 | status = simulate_llsc(regs, opcode); | 1067 | status = SIGSEGV; |
1068 | if (unlikely(get_user(mmop[1], epc) < 0)) | ||
1069 | status = SIGSEGV; | ||
1070 | opcode = (mmop[0] << 16) | mmop[1]; | ||
1001 | 1071 | ||
1002 | if (status < 0) | 1072 | if (status < 0) |
1003 | status = simulate_rdhwr(regs, opcode); | 1073 | status = simulate_rdhwr_mm(regs, opcode); |
1074 | } else { | ||
1075 | if (unlikely(get_user(opcode, epc) < 0)) | ||
1076 | status = SIGSEGV; | ||
1077 | |||
1078 | if (!cpu_has_llsc && status < 0) | ||
1079 | status = simulate_llsc(regs, opcode); | ||
1080 | |||
1081 | if (status < 0) | ||
1082 | status = simulate_rdhwr_normal(regs, opcode); | ||
1083 | } | ||
1004 | 1084 | ||
1005 | if (status < 0) | 1085 | if (status < 0) |
1006 | status = SIGILL; | 1086 | status = SIGILL; |
1007 | 1087 | ||
1008 | if (unlikely(status > 0)) { | 1088 | if (unlikely(status > 0)) { |
1009 | regs->cp0_epc = old_epc; /* Undo skip-over. */ | 1089 | regs->cp0_epc = old_epc; /* Undo skip-over. */ |
1090 | regs->regs[31] = old31; | ||
1010 | force_sig(status, current); | 1091 | force_sig(status, current); |
1011 | } | 1092 | } |
1012 | 1093 | ||
@@ -1320,7 +1401,7 @@ asmlinkage void cache_parity_error(void) | |||
1320 | void ejtag_exception_handler(struct pt_regs *regs) | 1401 | void ejtag_exception_handler(struct pt_regs *regs) |
1321 | { | 1402 | { |
1322 | const int field = 2 * sizeof(unsigned long); | 1403 | const int field = 2 * sizeof(unsigned long); |
1323 | unsigned long depc, old_epc; | 1404 | unsigned long depc, old_epc, old_ra; |
1324 | unsigned int debug; | 1405 | unsigned int debug; |
1325 | 1406 | ||
1326 | printk(KERN_DEBUG "SDBBP EJTAG debug exception - not handled yet, just ignored!\n"); | 1407 | printk(KERN_DEBUG "SDBBP EJTAG debug exception - not handled yet, just ignored!\n"); |
@@ -1335,10 +1416,12 @@ void ejtag_exception_handler(struct pt_regs *regs) | |||
1335 | * calculation. | 1416 | * calculation. |
1336 | */ | 1417 | */ |
1337 | old_epc = regs->cp0_epc; | 1418 | old_epc = regs->cp0_epc; |
1419 | old_ra = regs->regs[31]; | ||
1338 | regs->cp0_epc = depc; | 1420 | regs->cp0_epc = depc; |
1339 | __compute_return_epc(regs); | 1421 | compute_return_epc(regs); |
1340 | depc = regs->cp0_epc; | 1422 | depc = regs->cp0_epc; |
1341 | regs->cp0_epc = old_epc; | 1423 | regs->cp0_epc = old_epc; |
1424 | regs->regs[31] = old_ra; | ||
1342 | } else | 1425 | } else |
1343 | depc += 4; | 1426 | depc += 4; |
1344 | write_c0_depc(depc); | 1427 | write_c0_depc(depc); |
@@ -1377,11 +1460,27 @@ unsigned long vi_handlers[64]; | |||
1377 | void __init *set_except_vector(int n, void *addr) | 1460 | void __init *set_except_vector(int n, void *addr) |
1378 | { | 1461 | { |
1379 | unsigned long handler = (unsigned long) addr; | 1462 | unsigned long handler = (unsigned long) addr; |
1380 | unsigned long old_handler = exception_handlers[n]; | 1463 | unsigned long old_handler; |
1464 | |||
1465 | #ifdef CONFIG_CPU_MICROMIPS | ||
1466 | /* | ||
1467 | * Only the TLB handlers are cache aligned with an even | ||
1468 | * address. All other handlers are on an odd address and | ||
1469 | * require no modification. Otherwise, MIPS32 mode will | ||
1470 | * be entered when handling any TLB exceptions. That | ||
1471 | * would be bad...since we must stay in microMIPS mode. | ||
1472 | */ | ||
1473 | if (!(handler & 0x1)) | ||
1474 | handler |= 1; | ||
1475 | #endif | ||
1476 | old_handler = xchg(&exception_handlers[n], handler); | ||
1381 | 1477 | ||
1382 | exception_handlers[n] = handler; | ||
1383 | if (n == 0 && cpu_has_divec) { | 1478 | if (n == 0 && cpu_has_divec) { |
1479 | #ifdef CONFIG_CPU_MICROMIPS | ||
1480 | unsigned long jump_mask = ~((1 << 27) - 1); | ||
1481 | #else | ||
1384 | unsigned long jump_mask = ~((1 << 28) - 1); | 1482 | unsigned long jump_mask = ~((1 << 28) - 1); |
1483 | #endif | ||
1385 | u32 *buf = (u32 *)(ebase + 0x200); | 1484 | u32 *buf = (u32 *)(ebase + 0x200); |
1386 | unsigned int k0 = 26; | 1485 | unsigned int k0 = 26; |
1387 | if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) { | 1486 | if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) { |
@@ -1397,7 +1496,7 @@ void __init *set_except_vector(int n, void *addr) | |||
1397 | return (void *)old_handler; | 1496 | return (void *)old_handler; |
1398 | } | 1497 | } |
1399 | 1498 | ||
1400 | static asmlinkage void do_default_vi(void) | 1499 | static void do_default_vi(void) |
1401 | { | 1500 | { |
1402 | show_regs(get_irq_regs()); | 1501 | show_regs(get_irq_regs()); |
1403 | panic("Caught unexpected vectored interrupt."); | 1502 | panic("Caught unexpected vectored interrupt."); |
@@ -1408,17 +1507,18 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
1408 | unsigned long handler; | 1507 | unsigned long handler; |
1409 | unsigned long old_handler = vi_handlers[n]; | 1508 | unsigned long old_handler = vi_handlers[n]; |
1410 | int srssets = current_cpu_data.srsets; | 1509 | int srssets = current_cpu_data.srsets; |
1411 | u32 *w; | 1510 | u16 *h; |
1412 | unsigned char *b; | 1511 | unsigned char *b; |
1413 | 1512 | ||
1414 | BUG_ON(!cpu_has_veic && !cpu_has_vint); | 1513 | BUG_ON(!cpu_has_veic && !cpu_has_vint); |
1514 | BUG_ON((n < 0) && (n > 9)); | ||
1415 | 1515 | ||
1416 | if (addr == NULL) { | 1516 | if (addr == NULL) { |
1417 | handler = (unsigned long) do_default_vi; | 1517 | handler = (unsigned long) do_default_vi; |
1418 | srs = 0; | 1518 | srs = 0; |
1419 | } else | 1519 | } else |
1420 | handler = (unsigned long) addr; | 1520 | handler = (unsigned long) addr; |
1421 | vi_handlers[n] = (unsigned long) addr; | 1521 | vi_handlers[n] = handler; |
1422 | 1522 | ||
1423 | b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING); | 1523 | b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING); |
1424 | 1524 | ||
@@ -1437,9 +1537,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
1437 | if (srs == 0) { | 1537 | if (srs == 0) { |
1438 | /* | 1538 | /* |
1439 | * If no shadow set is selected then use the default handler | 1539 | * If no shadow set is selected then use the default handler |
1440 | * that does normal register saving and a standard interrupt exit | 1540 | * that does normal register saving and standard interrupt exit |
1441 | */ | 1541 | */ |
1442 | |||
1443 | extern char except_vec_vi, except_vec_vi_lui; | 1542 | extern char except_vec_vi, except_vec_vi_lui; |
1444 | extern char except_vec_vi_ori, except_vec_vi_end; | 1543 | extern char except_vec_vi_ori, except_vec_vi_end; |
1445 | extern char rollback_except_vec_vi; | 1544 | extern char rollback_except_vec_vi; |
@@ -1452,11 +1551,20 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
1452 | * Status.IM bit to be masked before going there. | 1551 | * Status.IM bit to be masked before going there. |
1453 | */ | 1552 | */ |
1454 | extern char except_vec_vi_mori; | 1553 | extern char except_vec_vi_mori; |
1554 | #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN) | ||
1555 | const int mori_offset = &except_vec_vi_mori - vec_start + 2; | ||
1556 | #else | ||
1455 | const int mori_offset = &except_vec_vi_mori - vec_start; | 1557 | const int mori_offset = &except_vec_vi_mori - vec_start; |
1558 | #endif | ||
1456 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1559 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1457 | const int handler_len = &except_vec_vi_end - vec_start; | 1560 | #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN) |
1561 | const int lui_offset = &except_vec_vi_lui - vec_start + 2; | ||
1562 | const int ori_offset = &except_vec_vi_ori - vec_start + 2; | ||
1563 | #else | ||
1458 | const int lui_offset = &except_vec_vi_lui - vec_start; | 1564 | const int lui_offset = &except_vec_vi_lui - vec_start; |
1459 | const int ori_offset = &except_vec_vi_ori - vec_start; | 1565 | const int ori_offset = &except_vec_vi_ori - vec_start; |
1566 | #endif | ||
1567 | const int handler_len = &except_vec_vi_end - vec_start; | ||
1460 | 1568 | ||
1461 | if (handler_len > VECTORSPACING) { | 1569 | if (handler_len > VECTORSPACING) { |
1462 | /* | 1570 | /* |
@@ -1466,30 +1574,44 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
1466 | panic("VECTORSPACING too small"); | 1574 | panic("VECTORSPACING too small"); |
1467 | } | 1575 | } |
1468 | 1576 | ||
1469 | memcpy(b, vec_start, handler_len); | 1577 | set_handler(((unsigned long)b - ebase), vec_start, |
1578 | #ifdef CONFIG_CPU_MICROMIPS | ||
1579 | (handler_len - 1)); | ||
1580 | #else | ||
1581 | handler_len); | ||
1582 | #endif | ||
1470 | #ifdef CONFIG_MIPS_MT_SMTC | 1583 | #ifdef CONFIG_MIPS_MT_SMTC |
1471 | BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ | 1584 | BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ |
1472 | 1585 | ||
1473 | w = (u32 *)(b + mori_offset); | 1586 | h = (u16 *)(b + mori_offset); |
1474 | *w = (*w & 0xffff0000) | (0x100 << n); | 1587 | *h = (0x100 << n); |
1475 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1588 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1476 | w = (u32 *)(b + lui_offset); | 1589 | h = (u16 *)(b + lui_offset); |
1477 | *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); | 1590 | *h = (handler >> 16) & 0xffff; |
1478 | w = (u32 *)(b + ori_offset); | 1591 | h = (u16 *)(b + ori_offset); |
1479 | *w = (*w & 0xffff0000) | ((u32)handler & 0xffff); | 1592 | *h = (handler & 0xffff); |
1480 | local_flush_icache_range((unsigned long)b, | 1593 | local_flush_icache_range((unsigned long)b, |
1481 | (unsigned long)(b+handler_len)); | 1594 | (unsigned long)(b+handler_len)); |
1482 | } | 1595 | } |
1483 | else { | 1596 | else { |
1484 | /* | 1597 | /* |
1485 | * In other cases jump directly to the interrupt handler | 1598 | * In other cases jump directly to the interrupt handler. It |
1486 | * | 1599 | * is the handler's responsibility to save registers if required |
1487 | * It is the handlers responsibility to save registers if required | 1600 | * (eg hi/lo) and return from the exception using "eret". |
1488 | * (eg hi/lo) and return from the exception using "eret" | ||
1489 | */ | 1601 | */ |
1490 | w = (u32 *)b; | 1602 | u32 insn; |
1491 | *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */ | 1603 | |
1492 | *w = 0; | 1604 | h = (u16 *)b; |
1605 | /* j handler */ | ||
1606 | #ifdef CONFIG_CPU_MICROMIPS | ||
1607 | insn = 0xd4000000 | (((u32)handler & 0x07ffffff) >> 1); | ||
1608 | #else | ||
1609 | insn = 0x08000000 | (((u32)handler & 0x0fffffff) >> 2); | ||
1610 | #endif | ||
1611 | h[0] = (insn >> 16) & 0xffff; | ||
1612 | h[1] = insn & 0xffff; | ||
1613 | h[2] = 0; | ||
1614 | h[3] = 0; | ||
1493 | local_flush_icache_range((unsigned long)b, | 1615 | local_flush_icache_range((unsigned long)b, |
1494 | (unsigned long)(b+8)); | 1616 | (unsigned long)(b+8)); |
1495 | } | 1617 | } |
@@ -1534,6 +1656,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) | |||
1534 | unsigned int cpu = smp_processor_id(); | 1656 | unsigned int cpu = smp_processor_id(); |
1535 | unsigned int status_set = ST0_CU0; | 1657 | unsigned int status_set = ST0_CU0; |
1536 | unsigned int hwrena = cpu_hwrena_impl_bits; | 1658 | unsigned int hwrena = cpu_hwrena_impl_bits; |
1659 | unsigned long asid = 0; | ||
1537 | #ifdef CONFIG_MIPS_MT_SMTC | 1660 | #ifdef CONFIG_MIPS_MT_SMTC |
1538 | int secondaryTC = 0; | 1661 | int secondaryTC = 0; |
1539 | int bootTC = (cpu == 0); | 1662 | int bootTC = (cpu == 0); |
@@ -1617,8 +1740,9 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) | |||
1617 | } | 1740 | } |
1618 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1741 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1619 | 1742 | ||
1620 | if (!cpu_data[cpu].asid_cache) | 1743 | asid = ASID_FIRST_VERSION; |
1621 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; | 1744 | cpu_data[cpu].asid_cache = asid; |
1745 | TLBMISS_HANDLER_SETUP(); | ||
1622 | 1746 | ||
1623 | atomic_inc(&init_mm.mm_count); | 1747 | atomic_inc(&init_mm.mm_count); |
1624 | current->active_mm = &init_mm; | 1748 | current->active_mm = &init_mm; |
@@ -1648,7 +1772,11 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) | |||
1648 | /* Install CPU exception handler */ | 1772 | /* Install CPU exception handler */ |
1649 | void __cpuinit set_handler(unsigned long offset, void *addr, unsigned long size) | 1773 | void __cpuinit set_handler(unsigned long offset, void *addr, unsigned long size) |
1650 | { | 1774 | { |
1775 | #ifdef CONFIG_CPU_MICROMIPS | ||
1776 | memcpy((void *)(ebase + offset), ((unsigned char *)addr - 1), size); | ||
1777 | #else | ||
1651 | memcpy((void *)(ebase + offset), addr, size); | 1778 | memcpy((void *)(ebase + offset), addr, size); |
1779 | #endif | ||
1652 | local_flush_icache_range(ebase + offset, ebase + offset + size); | 1780 | local_flush_icache_range(ebase + offset, ebase + offset + size); |
1653 | } | 1781 | } |
1654 | 1782 | ||
@@ -1682,8 +1810,9 @@ __setup("rdhwr_noopt", set_rdhwr_noopt); | |||
1682 | 1810 | ||
1683 | void __init trap_init(void) | 1811 | void __init trap_init(void) |
1684 | { | 1812 | { |
1685 | extern char except_vec3_generic, except_vec3_r4000; | 1813 | extern char except_vec3_generic; |
1686 | extern char except_vec4; | 1814 | extern char except_vec4; |
1815 | extern char except_vec3_r4000; | ||
1687 | unsigned long i; | 1816 | unsigned long i; |
1688 | int rollback; | 1817 | int rollback; |
1689 | 1818 | ||
@@ -1700,7 +1829,12 @@ void __init trap_init(void) | |||
1700 | ebase = (unsigned long) | 1829 | ebase = (unsigned long) |
1701 | __alloc_bootmem(size, 1 << fls(size), 0); | 1830 | __alloc_bootmem(size, 1 << fls(size), 0); |
1702 | } else { | 1831 | } else { |
1703 | ebase = CKSEG0; | 1832 | #ifdef CONFIG_KVM_GUEST |
1833 | #define KVM_GUEST_KSEG0 0x40000000 | ||
1834 | ebase = KVM_GUEST_KSEG0; | ||
1835 | #else | ||
1836 | ebase = CKSEG0; | ||
1837 | #endif | ||
1704 | if (cpu_has_mips_r2) | 1838 | if (cpu_has_mips_r2) |
1705 | ebase += (read_c0_ebase() & 0x3ffff000); | 1839 | ebase += (read_c0_ebase() & 0x3ffff000); |
1706 | } | 1840 | } |
@@ -1816,11 +1950,11 @@ void __init trap_init(void) | |||
1816 | 1950 | ||
1817 | if (cpu_has_vce) | 1951 | if (cpu_has_vce) |
1818 | /* Special exception: R4[04]00 uses also the divec space. */ | 1952 | /* Special exception: R4[04]00 uses also the divec space. */ |
1819 | memcpy((void *)(ebase + 0x180), &except_vec3_r4000, 0x100); | 1953 | set_handler(0x180, &except_vec3_r4000, 0x100); |
1820 | else if (cpu_has_4kex) | 1954 | else if (cpu_has_4kex) |
1821 | memcpy((void *)(ebase + 0x180), &except_vec3_generic, 0x80); | 1955 | set_handler(0x180, &except_vec3_generic, 0x80); |
1822 | else | 1956 | else |
1823 | memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80); | 1957 | set_handler(0x080, &except_vec3_generic, 0x80); |
1824 | 1958 | ||
1825 | local_flush_icache_range(ebase, ebase + 0x400); | 1959 | local_flush_icache_range(ebase, ebase + 0x400); |
1826 | flush_tlb_handlers(); | 1960 | flush_tlb_handlers(); |