| .. | .. |
|---|
| 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; |
|---|