.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * cp1emu.c: a MIPS coprocessor 1 (FPU) instruction emulator |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | * |
---|
7 | 8 | * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com |
---|
8 | 9 | * Copyright (C) 2000 MIPS Technologies, Inc. |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can distribute it and/or modify it |
---|
11 | | - * under the terms of the GNU General Public License (Version 2) as |
---|
12 | | - * published by the Free Software Foundation. |
---|
13 | | - * |
---|
14 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
---|
15 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
16 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
---|
17 | | - * for more details. |
---|
18 | | - * |
---|
19 | | - * You should have received a copy of the GNU General Public License along |
---|
20 | | - * with this program; if not, write to the Free Software Foundation, Inc., |
---|
21 | | - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
---|
22 | 10 | * |
---|
23 | 11 | * A complete emulator for MIPS coprocessor 1 instructions. This is |
---|
24 | 12 | * required for #float(switch) or #float(trap), where it catches all |
---|
.. | .. |
---|
451 | 439 | regs->cp0_epc + dec_insn.pc_inc + |
---|
452 | 440 | dec_insn.next_pc_inc; |
---|
453 | 441 | } |
---|
454 | | - /* fall through */ |
---|
| 442 | + fallthrough; |
---|
455 | 443 | case jr_op: |
---|
456 | 444 | /* For R6, JR already emulated in jalr_op */ |
---|
457 | 445 | if (NO_R6EMU && insn.r_format.func == jr_op) |
---|
.. | .. |
---|
471 | 459 | regs->regs[31] = regs->cp0_epc + |
---|
472 | 460 | dec_insn.pc_inc + |
---|
473 | 461 | dec_insn.next_pc_inc; |
---|
474 | | - /* fall through */ |
---|
| 462 | + fallthrough; |
---|
475 | 463 | case bltzl_op: |
---|
476 | 464 | if (NO_R6EMU) |
---|
477 | 465 | break; |
---|
478 | | - /* fall through */ |
---|
| 466 | + fallthrough; |
---|
479 | 467 | case bltz_op: |
---|
480 | 468 | if ((long)regs->regs[insn.i_format.rs] < 0) |
---|
481 | 469 | *contpc = regs->cp0_epc + |
---|
.. | .. |
---|
495 | 483 | regs->regs[31] = regs->cp0_epc + |
---|
496 | 484 | dec_insn.pc_inc + |
---|
497 | 485 | dec_insn.next_pc_inc; |
---|
498 | | - /* fall through */ |
---|
| 486 | + fallthrough; |
---|
499 | 487 | case bgezl_op: |
---|
500 | 488 | if (NO_R6EMU) |
---|
501 | 489 | break; |
---|
502 | | - /* fall through */ |
---|
| 490 | + fallthrough; |
---|
503 | 491 | case bgez_op: |
---|
504 | 492 | if ((long)regs->regs[insn.i_format.rs] >= 0) |
---|
505 | 493 | *contpc = regs->cp0_epc + |
---|
.. | .. |
---|
514 | 502 | break; |
---|
515 | 503 | case jalx_op: |
---|
516 | 504 | set_isa16_mode(bit); |
---|
517 | | - /* fall through */ |
---|
| 505 | + fallthrough; |
---|
518 | 506 | case jal_op: |
---|
519 | 507 | regs->regs[31] = regs->cp0_epc + |
---|
520 | 508 | dec_insn.pc_inc + |
---|
521 | 509 | dec_insn.next_pc_inc; |
---|
522 | | - /* fall through */ |
---|
| 510 | + fallthrough; |
---|
523 | 511 | case j_op: |
---|
524 | 512 | *contpc = regs->cp0_epc + dec_insn.pc_inc; |
---|
525 | 513 | *contpc >>= 28; |
---|
.. | .. |
---|
531 | 519 | case beql_op: |
---|
532 | 520 | if (NO_R6EMU) |
---|
533 | 521 | break; |
---|
534 | | - /* fall through */ |
---|
| 522 | + fallthrough; |
---|
535 | 523 | case beq_op: |
---|
536 | 524 | if (regs->regs[insn.i_format.rs] == |
---|
537 | 525 | regs->regs[insn.i_format.rt]) |
---|
.. | .. |
---|
546 | 534 | case bnel_op: |
---|
547 | 535 | if (NO_R6EMU) |
---|
548 | 536 | break; |
---|
549 | | - /* fall through */ |
---|
| 537 | + fallthrough; |
---|
550 | 538 | case bne_op: |
---|
551 | 539 | if (regs->regs[insn.i_format.rs] != |
---|
552 | 540 | regs->regs[insn.i_format.rt]) |
---|
.. | .. |
---|
561 | 549 | case blezl_op: |
---|
562 | 550 | if (!insn.i_format.rt && NO_R6EMU) |
---|
563 | 551 | break; |
---|
564 | | - /* fall through */ |
---|
| 552 | + fallthrough; |
---|
565 | 553 | case blez_op: |
---|
566 | 554 | |
---|
567 | 555 | /* |
---|
.. | .. |
---|
599 | 587 | case bgtzl_op: |
---|
600 | 588 | if (!insn.i_format.rt && NO_R6EMU) |
---|
601 | 589 | break; |
---|
602 | | - /* fall through */ |
---|
| 590 | + fallthrough; |
---|
603 | 591 | case bgtz_op: |
---|
604 | 592 | /* |
---|
605 | 593 | * Compact branches for R6 for the |
---|
.. | .. |
---|
737 | 725 | return 1; |
---|
738 | 726 | } |
---|
739 | 727 | /* R2/R6 compatible cop1 instruction */ |
---|
740 | | - /* fall through */ |
---|
| 728 | + fallthrough; |
---|
741 | 729 | case cop2_op: |
---|
742 | 730 | case cop1x_op: |
---|
743 | 731 | if (insn.i_format.rs == bc_op) { |
---|
.. | .. |
---|
1063 | 1051 | MIPSInst_SIMM(ir)); |
---|
1064 | 1052 | MIPS_FPU_EMU_INC_STATS(loads); |
---|
1065 | 1053 | |
---|
1066 | | - if (!access_ok(VERIFY_READ, dva, sizeof(u64))) { |
---|
| 1054 | + if (!access_ok(dva, sizeof(u64))) { |
---|
1067 | 1055 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1068 | 1056 | *fault_addr = dva; |
---|
1069 | 1057 | return SIGBUS; |
---|
.. | .. |
---|
1081 | 1069 | MIPSInst_SIMM(ir)); |
---|
1082 | 1070 | MIPS_FPU_EMU_INC_STATS(stores); |
---|
1083 | 1071 | DIFROMREG(dval, MIPSInst_RT(ir)); |
---|
1084 | | - if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) { |
---|
| 1072 | + if (!access_ok(dva, sizeof(u64))) { |
---|
1085 | 1073 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1086 | 1074 | *fault_addr = dva; |
---|
1087 | 1075 | return SIGBUS; |
---|
.. | .. |
---|
1097 | 1085 | wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + |
---|
1098 | 1086 | MIPSInst_SIMM(ir)); |
---|
1099 | 1087 | MIPS_FPU_EMU_INC_STATS(loads); |
---|
1100 | | - if (!access_ok(VERIFY_READ, wva, sizeof(u32))) { |
---|
| 1088 | + if (!access_ok(wva, sizeof(u32))) { |
---|
1101 | 1089 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1102 | 1090 | *fault_addr = wva; |
---|
1103 | 1091 | return SIGBUS; |
---|
.. | .. |
---|
1115 | 1103 | MIPSInst_SIMM(ir)); |
---|
1116 | 1104 | MIPS_FPU_EMU_INC_STATS(stores); |
---|
1117 | 1105 | SIFROMREG(wval, MIPSInst_RT(ir)); |
---|
1118 | | - if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) { |
---|
| 1106 | + if (!access_ok(wva, sizeof(u32))) { |
---|
1119 | 1107 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1120 | 1108 | *fault_addr = wva; |
---|
1121 | 1109 | return SIGBUS; |
---|
.. | .. |
---|
1229 | 1217 | case bcfl_op: |
---|
1230 | 1218 | if (cpu_has_mips_2_3_4_5_r) |
---|
1231 | 1219 | likely = 1; |
---|
1232 | | - /* fall through */ |
---|
| 1220 | + fallthrough; |
---|
1233 | 1221 | case bcf_op: |
---|
1234 | 1222 | cond = !cond; |
---|
1235 | 1223 | break; |
---|
1236 | 1224 | case bctl_op: |
---|
1237 | 1225 | if (cpu_has_mips_2_3_4_5_r) |
---|
1238 | 1226 | likely = 1; |
---|
1239 | | - /* fall through */ |
---|
| 1227 | + fallthrough; |
---|
1240 | 1228 | case bct_op: |
---|
1241 | 1229 | break; |
---|
1242 | 1230 | } |
---|
.. | .. |
---|
1493 | 1481 | xcp->regs[MIPSInst_FT(ir)]); |
---|
1494 | 1482 | |
---|
1495 | 1483 | MIPS_FPU_EMU_INC_STATS(loads); |
---|
1496 | | - if (!access_ok(VERIFY_READ, va, sizeof(u32))) { |
---|
| 1484 | + if (!access_ok(va, sizeof(u32))) { |
---|
1497 | 1485 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1498 | 1486 | *fault_addr = va; |
---|
1499 | 1487 | return SIGBUS; |
---|
.. | .. |
---|
1513 | 1501 | MIPS_FPU_EMU_INC_STATS(stores); |
---|
1514 | 1502 | |
---|
1515 | 1503 | SIFROMREG(val, MIPSInst_FS(ir)); |
---|
1516 | | - if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { |
---|
| 1504 | + if (!access_ok(va, sizeof(u32))) { |
---|
1517 | 1505 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1518 | 1506 | *fault_addr = va; |
---|
1519 | 1507 | return SIGBUS; |
---|
.. | .. |
---|
1526 | 1514 | break; |
---|
1527 | 1515 | |
---|
1528 | 1516 | case madd_s_op: |
---|
1529 | | - handler = fpemu_sp_madd; |
---|
| 1517 | + if (cpu_has_mac2008_only) |
---|
| 1518 | + handler = ieee754sp_madd; |
---|
| 1519 | + else |
---|
| 1520 | + handler = fpemu_sp_madd; |
---|
1530 | 1521 | goto scoptop; |
---|
1531 | 1522 | case msub_s_op: |
---|
1532 | | - handler = fpemu_sp_msub; |
---|
| 1523 | + if (cpu_has_mac2008_only) |
---|
| 1524 | + handler = ieee754sp_msub; |
---|
| 1525 | + else |
---|
| 1526 | + handler = fpemu_sp_msub; |
---|
1533 | 1527 | goto scoptop; |
---|
1534 | 1528 | case nmadd_s_op: |
---|
1535 | | - handler = fpemu_sp_nmadd; |
---|
| 1529 | + if (cpu_has_mac2008_only) |
---|
| 1530 | + handler = ieee754sp_nmadd; |
---|
| 1531 | + else |
---|
| 1532 | + handler = fpemu_sp_nmadd; |
---|
1536 | 1533 | goto scoptop; |
---|
1537 | 1534 | case nmsub_s_op: |
---|
1538 | | - handler = fpemu_sp_nmsub; |
---|
| 1535 | + if (cpu_has_mac2008_only) |
---|
| 1536 | + handler = ieee754sp_nmsub; |
---|
| 1537 | + else |
---|
| 1538 | + handler = fpemu_sp_nmsub; |
---|
1539 | 1539 | goto scoptop; |
---|
1540 | 1540 | |
---|
1541 | 1541 | scoptop: |
---|
.. | .. |
---|
1590 | 1590 | xcp->regs[MIPSInst_FT(ir)]); |
---|
1591 | 1591 | |
---|
1592 | 1592 | MIPS_FPU_EMU_INC_STATS(loads); |
---|
1593 | | - if (!access_ok(VERIFY_READ, va, sizeof(u64))) { |
---|
| 1593 | + if (!access_ok(va, sizeof(u64))) { |
---|
1594 | 1594 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1595 | 1595 | *fault_addr = va; |
---|
1596 | 1596 | return SIGBUS; |
---|
.. | .. |
---|
1609 | 1609 | |
---|
1610 | 1610 | MIPS_FPU_EMU_INC_STATS(stores); |
---|
1611 | 1611 | DIFROMREG(val, MIPSInst_FS(ir)); |
---|
1612 | | - if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { |
---|
| 1612 | + if (!access_ok(va, sizeof(u64))) { |
---|
1613 | 1613 | MIPS_FPU_EMU_INC_STATS(errors); |
---|
1614 | 1614 | *fault_addr = va; |
---|
1615 | 1615 | return SIGBUS; |
---|
.. | .. |
---|
1622 | 1622 | break; |
---|
1623 | 1623 | |
---|
1624 | 1624 | case madd_d_op: |
---|
1625 | | - handler = fpemu_dp_madd; |
---|
| 1625 | + if (cpu_has_mac2008_only) |
---|
| 1626 | + handler = ieee754dp_madd; |
---|
| 1627 | + else |
---|
| 1628 | + handler = fpemu_dp_madd; |
---|
1626 | 1629 | goto dcoptop; |
---|
1627 | 1630 | case msub_d_op: |
---|
1628 | | - handler = fpemu_dp_msub; |
---|
| 1631 | + if (cpu_has_mac2008_only) |
---|
| 1632 | + handler = ieee754dp_msub; |
---|
| 1633 | + else |
---|
| 1634 | + handler = fpemu_dp_msub; |
---|
1629 | 1635 | goto dcoptop; |
---|
1630 | 1636 | case nmadd_d_op: |
---|
1631 | | - handler = fpemu_dp_nmadd; |
---|
| 1637 | + if (cpu_has_mac2008_only) |
---|
| 1638 | + handler = ieee754dp_nmadd; |
---|
| 1639 | + else |
---|
| 1640 | + handler = fpemu_dp_nmadd; |
---|
1632 | 1641 | goto dcoptop; |
---|
1633 | 1642 | case nmsub_d_op: |
---|
| 1643 | + if (cpu_has_mac2008_only) |
---|
| 1644 | + handler = ieee754dp_nmsub; |
---|
| 1645 | + else |
---|
1634 | 1646 | handler = fpemu_dp_nmsub; |
---|
1635 | 1647 | goto dcoptop; |
---|
1636 | 1648 | |
---|
.. | .. |
---|
2831 | 2843 | u16 *instr_ptr; |
---|
2832 | 2844 | int sig = 0; |
---|
2833 | 2845 | |
---|
| 2846 | + /* |
---|
| 2847 | + * Initialize context if it hasn't been used already, otherwise ensure |
---|
| 2848 | + * it has been saved to struct thread_struct. |
---|
| 2849 | + */ |
---|
| 2850 | + if (!init_fp_ctx(current)) |
---|
| 2851 | + lose_fpu(1); |
---|
| 2852 | + |
---|
2834 | 2853 | oldepc = xcp->cp0_epc; |
---|
2835 | 2854 | do { |
---|
2836 | 2855 | prevepc = xcp->cp0_epc; |
---|