MIPS: traps.c: Don't emulate RDHWR in the CpU #0 exception handler

In the regular MIPS instruction set RDHWR is encoded with the SPECIAL3
(011111) major opcode.  Therefore it cannot trigger the CpU (Coprocessor
Unusable) exception, and certainly not for coprocessor 0, as the opcode
does not overlap with any of the older ISA reservations, i.e. LWC0
(110000), SWC0 (111000), LDC0 (110100) or SDC0 (111100).  The closest
match might be SDC3 (111111), possibly causing a CpU #3 exception,
however our code does not handle it anyway.  A quick check with a MIPS I
and a MIPS III processor:

CPU0 revision is: 00000220 (R3000)
CPU0 revision is: 00000440 (R4400SC)

indeed indicates that the RI (Reserved Instruction) exception is
triggered.  It's only LL and SC that require emulation in the CpU #0
exception handler as they reuse the LWC0 and SWC0 opcodes respectively.

In the microMIPS instruction set RDHWR is mandatory and triggering the
RI exception is required on unimplemented or disabled register accesses.
Therefore emulating the microMIPS instruction in the CpU #0 exception
handler is not required either.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/12280/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Maciej W. Rozycki 2016-01-30 09:08:16 +00:00 committed by Ralf Baechle
parent 87bee0ecf0
commit 10f6d99f0f

View File

@ -1369,26 +1369,12 @@ asmlinkage void do_cpu(struct pt_regs *regs)
if (unlikely(compute_return_epc(regs) < 0)) if (unlikely(compute_return_epc(regs) < 0))
break; break;
if (get_isa16_mode(regs->cp0_epc)) { if (!get_isa16_mode(regs->cp0_epc)) {
unsigned short mmop[2] = { 0 };
if (unlikely(get_user(mmop[0], epc) < 0))
status = SIGSEGV;
if (unlikely(get_user(mmop[1], epc) < 0))
status = SIGSEGV;
opcode = (mmop[0] << 16) | mmop[1];
if (status < 0)
status = simulate_rdhwr_mm(regs, opcode);
} else {
if (unlikely(get_user(opcode, epc) < 0)) if (unlikely(get_user(opcode, epc) < 0))
status = SIGSEGV; status = SIGSEGV;
if (!cpu_has_llsc && status < 0) if (!cpu_has_llsc && status < 0)
status = simulate_llsc(regs, opcode); status = simulate_llsc(regs, opcode);
if (status < 0)
status = simulate_rdhwr_normal(regs, opcode);
} }
if (status < 0) if (status < 0)