diff options
-rw-r--r-- | arch/mips/include/asm/branch.h | 18 | ||||
-rw-r--r-- | arch/mips/kernel/branch.c | 196 | ||||
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 201 |
3 files changed, 214 insertions, 201 deletions
diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index d109e34130f5..de781cf54bc7 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h | |||
@@ -20,6 +20,24 @@ extern int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
20 | extern int __microMIPS_compute_return_epc(struct pt_regs *regs); | 20 | extern int __microMIPS_compute_return_epc(struct pt_regs *regs); |
21 | extern int __MIPS16e_compute_return_epc(struct pt_regs *regs); | 21 | extern int __MIPS16e_compute_return_epc(struct pt_regs *regs); |
22 | 22 | ||
23 | /* | ||
24 | * microMIPS bitfields | ||
25 | */ | ||
26 | #define MM_POOL32A_MINOR_MASK 0x3f | ||
27 | #define MM_POOL32A_MINOR_SHIFT 0x6 | ||
28 | #define MM_MIPS32_COND_FC 0x30 | ||
29 | |||
30 | extern int __mm_isBranchInstr(struct pt_regs *regs, | ||
31 | struct mm_decoded_insn dec_insn, unsigned long *contpc); | ||
32 | |||
33 | static inline int mm_isBranchInstr(struct pt_regs *regs, | ||
34 | struct mm_decoded_insn dec_insn, unsigned long *contpc) | ||
35 | { | ||
36 | if (!cpu_has_mmips) | ||
37 | return 0; | ||
38 | |||
39 | return __mm_isBranchInstr(regs, dec_insn, contpc); | ||
40 | } | ||
23 | 41 | ||
24 | static inline int delay_slot(struct pt_regs *regs) | 42 | static inline int delay_slot(struct pt_regs *regs) |
25 | { | 43 | { |
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 4d78bf445a9c..84888d9332b9 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c | |||
@@ -48,6 +48,202 @@ int __isa_exception_epc(struct pt_regs *regs) | |||
48 | return epc; | 48 | return epc; |
49 | } | 49 | } |
50 | 50 | ||
51 | /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ | ||
52 | static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; | ||
53 | |||
54 | int __mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | ||
55 | unsigned long *contpc) | ||
56 | { | ||
57 | union mips_instruction insn = (union mips_instruction)dec_insn.insn; | ||
58 | int bc_false = 0; | ||
59 | unsigned int fcr31; | ||
60 | unsigned int bit; | ||
61 | |||
62 | if (!cpu_has_mmips) | ||
63 | return 0; | ||
64 | |||
65 | switch (insn.mm_i_format.opcode) { | ||
66 | case mm_pool32a_op: | ||
67 | if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == | ||
68 | mm_pool32axf_op) { | ||
69 | switch (insn.mm_i_format.simmediate >> | ||
70 | MM_POOL32A_MINOR_SHIFT) { | ||
71 | case mm_jalr_op: | ||
72 | case mm_jalrhb_op: | ||
73 | case mm_jalrs_op: | ||
74 | case mm_jalrshb_op: | ||
75 | if (insn.mm_i_format.rt != 0) /* Not mm_jr */ | ||
76 | regs->regs[insn.mm_i_format.rt] = | ||
77 | regs->cp0_epc + | ||
78 | dec_insn.pc_inc + | ||
79 | dec_insn.next_pc_inc; | ||
80 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
81 | return 1; | ||
82 | } | ||
83 | } | ||
84 | break; | ||
85 | case mm_pool32i_op: | ||
86 | switch (insn.mm_i_format.rt) { | ||
87 | case mm_bltzals_op: | ||
88 | case mm_bltzal_op: | ||
89 | regs->regs[31] = regs->cp0_epc + | ||
90 | dec_insn.pc_inc + | ||
91 | dec_insn.next_pc_inc; | ||
92 | /* Fall through */ | ||
93 | case mm_bltz_op: | ||
94 | if ((long)regs->regs[insn.mm_i_format.rs] < 0) | ||
95 | *contpc = regs->cp0_epc + | ||
96 | dec_insn.pc_inc + | ||
97 | (insn.mm_i_format.simmediate << 1); | ||
98 | else | ||
99 | *contpc = regs->cp0_epc + | ||
100 | dec_insn.pc_inc + | ||
101 | dec_insn.next_pc_inc; | ||
102 | return 1; | ||
103 | case mm_bgezals_op: | ||
104 | case mm_bgezal_op: | ||
105 | regs->regs[31] = regs->cp0_epc + | ||
106 | dec_insn.pc_inc + | ||
107 | dec_insn.next_pc_inc; | ||
108 | /* Fall through */ | ||
109 | case mm_bgez_op: | ||
110 | if ((long)regs->regs[insn.mm_i_format.rs] >= 0) | ||
111 | *contpc = regs->cp0_epc + | ||
112 | dec_insn.pc_inc + | ||
113 | (insn.mm_i_format.simmediate << 1); | ||
114 | else | ||
115 | *contpc = regs->cp0_epc + | ||
116 | dec_insn.pc_inc + | ||
117 | dec_insn.next_pc_inc; | ||
118 | return 1; | ||
119 | case mm_blez_op: | ||
120 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
121 | *contpc = regs->cp0_epc + | ||
122 | dec_insn.pc_inc + | ||
123 | (insn.mm_i_format.simmediate << 1); | ||
124 | else | ||
125 | *contpc = regs->cp0_epc + | ||
126 | dec_insn.pc_inc + | ||
127 | dec_insn.next_pc_inc; | ||
128 | return 1; | ||
129 | case mm_bgtz_op: | ||
130 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
131 | *contpc = regs->cp0_epc + | ||
132 | dec_insn.pc_inc + | ||
133 | (insn.mm_i_format.simmediate << 1); | ||
134 | else | ||
135 | *contpc = regs->cp0_epc + | ||
136 | dec_insn.pc_inc + | ||
137 | dec_insn.next_pc_inc; | ||
138 | return 1; | ||
139 | case mm_bc2f_op: | ||
140 | case mm_bc1f_op: | ||
141 | bc_false = 1; | ||
142 | /* Fall through */ | ||
143 | case mm_bc2t_op: | ||
144 | case mm_bc1t_op: | ||
145 | preempt_disable(); | ||
146 | if (is_fpu_owner()) | ||
147 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | ||
148 | else | ||
149 | fcr31 = current->thread.fpu.fcr31; | ||
150 | preempt_enable(); | ||
151 | |||
152 | if (bc_false) | ||
153 | fcr31 = ~fcr31; | ||
154 | |||
155 | bit = (insn.mm_i_format.rs >> 2); | ||
156 | bit += (bit != 0); | ||
157 | bit += 23; | ||
158 | if (fcr31 & (1 << bit)) | ||
159 | *contpc = regs->cp0_epc + | ||
160 | dec_insn.pc_inc + | ||
161 | (insn.mm_i_format.simmediate << 1); | ||
162 | else | ||
163 | *contpc = regs->cp0_epc + | ||
164 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
165 | return 1; | ||
166 | } | ||
167 | break; | ||
168 | case mm_pool16c_op: | ||
169 | switch (insn.mm_i_format.rt) { | ||
170 | case mm_jalr16_op: | ||
171 | case mm_jalrs16_op: | ||
172 | regs->regs[31] = regs->cp0_epc + | ||
173 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
174 | /* Fall through */ | ||
175 | case mm_jr16_op: | ||
176 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
177 | return 1; | ||
178 | } | ||
179 | break; | ||
180 | case mm_beqz16_op: | ||
181 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) | ||
182 | *contpc = regs->cp0_epc + | ||
183 | dec_insn.pc_inc + | ||
184 | (insn.mm_b1_format.simmediate << 1); | ||
185 | else | ||
186 | *contpc = regs->cp0_epc + | ||
187 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
188 | return 1; | ||
189 | case mm_bnez16_op: | ||
190 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) | ||
191 | *contpc = regs->cp0_epc + | ||
192 | dec_insn.pc_inc + | ||
193 | (insn.mm_b1_format.simmediate << 1); | ||
194 | else | ||
195 | *contpc = regs->cp0_epc + | ||
196 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
197 | return 1; | ||
198 | case mm_b16_op: | ||
199 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
200 | (insn.mm_b0_format.simmediate << 1); | ||
201 | return 1; | ||
202 | case mm_beq32_op: | ||
203 | if (regs->regs[insn.mm_i_format.rs] == | ||
204 | regs->regs[insn.mm_i_format.rt]) | ||
205 | *contpc = regs->cp0_epc + | ||
206 | dec_insn.pc_inc + | ||
207 | (insn.mm_i_format.simmediate << 1); | ||
208 | else | ||
209 | *contpc = regs->cp0_epc + | ||
210 | dec_insn.pc_inc + | ||
211 | dec_insn.next_pc_inc; | ||
212 | return 1; | ||
213 | case mm_bne32_op: | ||
214 | if (regs->regs[insn.mm_i_format.rs] != | ||
215 | regs->regs[insn.mm_i_format.rt]) | ||
216 | *contpc = regs->cp0_epc + | ||
217 | dec_insn.pc_inc + | ||
218 | (insn.mm_i_format.simmediate << 1); | ||
219 | else | ||
220 | *contpc = regs->cp0_epc + | ||
221 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
222 | return 1; | ||
223 | case mm_jalx32_op: | ||
224 | regs->regs[31] = regs->cp0_epc + | ||
225 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
226 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
227 | *contpc >>= 28; | ||
228 | *contpc <<= 28; | ||
229 | *contpc |= (insn.j_format.target << 2); | ||
230 | return 1; | ||
231 | case mm_jals32_op: | ||
232 | case mm_jal32_op: | ||
233 | regs->regs[31] = regs->cp0_epc + | ||
234 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
235 | /* Fall through */ | ||
236 | case mm_j32_op: | ||
237 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
238 | *contpc >>= 27; | ||
239 | *contpc <<= 27; | ||
240 | *contpc |= (insn.j_format.target << 1); | ||
241 | set_isa16_mode(*contpc); | ||
242 | return 1; | ||
243 | } | ||
244 | return 0; | ||
245 | } | ||
246 | |||
51 | /* | 247 | /* |
52 | * Compute return address and emulate branch in microMIPS mode after an | 248 | * Compute return address and emulate branch in microMIPS mode after an |
53 | * exception only. It does not handle compact branches/jumps and cannot | 249 | * exception only. It does not handle compact branches/jumps and cannot |
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 6258291354eb..b31ce6cdb6b9 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
@@ -67,11 +67,6 @@ static int fpux_emu(struct pt_regs *, | |||
67 | /* Determine rounding mode from the RM bits of the FCSR */ | 67 | /* Determine rounding mode from the RM bits of the FCSR */ |
68 | #define modeindex(v) ((v) & FPU_CSR_RM) | 68 | #define modeindex(v) ((v) & FPU_CSR_RM) |
69 | 69 | ||
70 | /* microMIPS bitfields */ | ||
71 | #define MM_POOL32A_MINOR_MASK 0x3f | ||
72 | #define MM_POOL32A_MINOR_SHIFT 0x6 | ||
73 | #define MM_MIPS32_COND_FC 0x30 | ||
74 | |||
75 | /* Convert MIPS rounding mode (0..3) to IEEE library modes. */ | 70 | /* Convert MIPS rounding mode (0..3) to IEEE library modes. */ |
76 | static const unsigned char ieee_rm[4] = { | 71 | static const unsigned char ieee_rm[4] = { |
77 | [FPU_CSR_RN] = IEEE754_RN, | 72 | [FPU_CSR_RN] = IEEE754_RN, |
@@ -99,9 +94,6 @@ static const unsigned int fpucondbit[8] = { | |||
99 | FPU_CSR_COND7 | 94 | FPU_CSR_COND7 |
100 | }; | 95 | }; |
101 | 96 | ||
102 | /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ | ||
103 | static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; | ||
104 | |||
105 | /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ | 97 | /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ |
106 | static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; | 98 | static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; |
107 | static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0}; | 99 | static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0}; |
@@ -449,199 +441,6 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) | |||
449 | return 0; | 441 | return 0; |
450 | } | 442 | } |
451 | 443 | ||
452 | int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | ||
453 | unsigned long *contpc) | ||
454 | { | ||
455 | union mips_instruction insn = (union mips_instruction)dec_insn.insn; | ||
456 | int bc_false = 0; | ||
457 | unsigned int fcr31; | ||
458 | unsigned int bit; | ||
459 | |||
460 | if (!cpu_has_mmips) | ||
461 | return 0; | ||
462 | |||
463 | switch (insn.mm_i_format.opcode) { | ||
464 | case mm_pool32a_op: | ||
465 | if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == | ||
466 | mm_pool32axf_op) { | ||
467 | switch (insn.mm_i_format.simmediate >> | ||
468 | MM_POOL32A_MINOR_SHIFT) { | ||
469 | case mm_jalr_op: | ||
470 | case mm_jalrhb_op: | ||
471 | case mm_jalrs_op: | ||
472 | case mm_jalrshb_op: | ||
473 | if (insn.mm_i_format.rt != 0) /* Not mm_jr */ | ||
474 | regs->regs[insn.mm_i_format.rt] = | ||
475 | regs->cp0_epc + | ||
476 | dec_insn.pc_inc + | ||
477 | dec_insn.next_pc_inc; | ||
478 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
479 | return 1; | ||
480 | } | ||
481 | } | ||
482 | break; | ||
483 | case mm_pool32i_op: | ||
484 | switch (insn.mm_i_format.rt) { | ||
485 | case mm_bltzals_op: | ||
486 | case mm_bltzal_op: | ||
487 | regs->regs[31] = regs->cp0_epc + | ||
488 | dec_insn.pc_inc + | ||
489 | dec_insn.next_pc_inc; | ||
490 | /* Fall through */ | ||
491 | case mm_bltz_op: | ||
492 | if ((long)regs->regs[insn.mm_i_format.rs] < 0) | ||
493 | *contpc = regs->cp0_epc + | ||
494 | dec_insn.pc_inc + | ||
495 | (insn.mm_i_format.simmediate << 1); | ||
496 | else | ||
497 | *contpc = regs->cp0_epc + | ||
498 | dec_insn.pc_inc + | ||
499 | dec_insn.next_pc_inc; | ||
500 | return 1; | ||
501 | case mm_bgezals_op: | ||
502 | case mm_bgezal_op: | ||
503 | regs->regs[31] = regs->cp0_epc + | ||
504 | dec_insn.pc_inc + | ||
505 | dec_insn.next_pc_inc; | ||
506 | /* Fall through */ | ||
507 | case mm_bgez_op: | ||
508 | if ((long)regs->regs[insn.mm_i_format.rs] >= 0) | ||
509 | *contpc = regs->cp0_epc + | ||
510 | dec_insn.pc_inc + | ||
511 | (insn.mm_i_format.simmediate << 1); | ||
512 | else | ||
513 | *contpc = regs->cp0_epc + | ||
514 | dec_insn.pc_inc + | ||
515 | dec_insn.next_pc_inc; | ||
516 | return 1; | ||
517 | case mm_blez_op: | ||
518 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
519 | *contpc = regs->cp0_epc + | ||
520 | dec_insn.pc_inc + | ||
521 | (insn.mm_i_format.simmediate << 1); | ||
522 | else | ||
523 | *contpc = regs->cp0_epc + | ||
524 | dec_insn.pc_inc + | ||
525 | dec_insn.next_pc_inc; | ||
526 | return 1; | ||
527 | case mm_bgtz_op: | ||
528 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
529 | *contpc = regs->cp0_epc + | ||
530 | dec_insn.pc_inc + | ||
531 | (insn.mm_i_format.simmediate << 1); | ||
532 | else | ||
533 | *contpc = regs->cp0_epc + | ||
534 | dec_insn.pc_inc + | ||
535 | dec_insn.next_pc_inc; | ||
536 | return 1; | ||
537 | case mm_bc2f_op: | ||
538 | case mm_bc1f_op: | ||
539 | bc_false = 1; | ||
540 | /* Fall through */ | ||
541 | case mm_bc2t_op: | ||
542 | case mm_bc1t_op: | ||
543 | preempt_disable(); | ||
544 | if (is_fpu_owner()) | ||
545 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | ||
546 | else | ||
547 | fcr31 = current->thread.fpu.fcr31; | ||
548 | preempt_enable(); | ||
549 | |||
550 | if (bc_false) | ||
551 | fcr31 = ~fcr31; | ||
552 | |||
553 | bit = (insn.mm_i_format.rs >> 2); | ||
554 | bit += (bit != 0); | ||
555 | bit += 23; | ||
556 | if (fcr31 & (1 << bit)) | ||
557 | *contpc = regs->cp0_epc + | ||
558 | dec_insn.pc_inc + | ||
559 | (insn.mm_i_format.simmediate << 1); | ||
560 | else | ||
561 | *contpc = regs->cp0_epc + | ||
562 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
563 | return 1; | ||
564 | } | ||
565 | break; | ||
566 | case mm_pool16c_op: | ||
567 | switch (insn.mm_i_format.rt) { | ||
568 | case mm_jalr16_op: | ||
569 | case mm_jalrs16_op: | ||
570 | regs->regs[31] = regs->cp0_epc + | ||
571 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
572 | /* Fall through */ | ||
573 | case mm_jr16_op: | ||
574 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
575 | return 1; | ||
576 | } | ||
577 | break; | ||
578 | case mm_beqz16_op: | ||
579 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) | ||
580 | *contpc = regs->cp0_epc + | ||
581 | dec_insn.pc_inc + | ||
582 | (insn.mm_b1_format.simmediate << 1); | ||
583 | else | ||
584 | *contpc = regs->cp0_epc + | ||
585 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
586 | return 1; | ||
587 | case mm_bnez16_op: | ||
588 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) | ||
589 | *contpc = regs->cp0_epc + | ||
590 | dec_insn.pc_inc + | ||
591 | (insn.mm_b1_format.simmediate << 1); | ||
592 | else | ||
593 | *contpc = regs->cp0_epc + | ||
594 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
595 | return 1; | ||
596 | case mm_b16_op: | ||
597 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
598 | (insn.mm_b0_format.simmediate << 1); | ||
599 | return 1; | ||
600 | case mm_beq32_op: | ||
601 | if (regs->regs[insn.mm_i_format.rs] == | ||
602 | regs->regs[insn.mm_i_format.rt]) | ||
603 | *contpc = regs->cp0_epc + | ||
604 | dec_insn.pc_inc + | ||
605 | (insn.mm_i_format.simmediate << 1); | ||
606 | else | ||
607 | *contpc = regs->cp0_epc + | ||
608 | dec_insn.pc_inc + | ||
609 | dec_insn.next_pc_inc; | ||
610 | return 1; | ||
611 | case mm_bne32_op: | ||
612 | if (regs->regs[insn.mm_i_format.rs] != | ||
613 | regs->regs[insn.mm_i_format.rt]) | ||
614 | *contpc = regs->cp0_epc + | ||
615 | dec_insn.pc_inc + | ||
616 | (insn.mm_i_format.simmediate << 1); | ||
617 | else | ||
618 | *contpc = regs->cp0_epc + | ||
619 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
620 | return 1; | ||
621 | case mm_jalx32_op: | ||
622 | regs->regs[31] = regs->cp0_epc + | ||
623 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
624 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
625 | *contpc >>= 28; | ||
626 | *contpc <<= 28; | ||
627 | *contpc |= (insn.j_format.target << 2); | ||
628 | return 1; | ||
629 | case mm_jals32_op: | ||
630 | case mm_jal32_op: | ||
631 | regs->regs[31] = regs->cp0_epc + | ||
632 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
633 | /* Fall through */ | ||
634 | case mm_j32_op: | ||
635 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
636 | *contpc >>= 27; | ||
637 | *contpc <<= 27; | ||
638 | *contpc |= (insn.j_format.target << 1); | ||
639 | set_isa16_mode(*contpc); | ||
640 | return 1; | ||
641 | } | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | /* | 444 | /* |
646 | * Redundant with logic already in kernel/branch.c, | 445 | * Redundant with logic already in kernel/branch.c, |
647 | * embedded in compute_return_epc. At some point, | 446 | * embedded in compute_return_epc. At some point, |