MIPS: unaligned: Add DSP lwx & lhx missaligned access support

Add handling of missaligned access for DSP load instructions
lwx & lhx.

Since DSP instructions share SPECIAL3 opcode with other non-DSP
instructions, necessary logic was inserted for distinguishing
between instructions with SPECIAL3 opcode. For that purpose,
the instruction format for DSP instructions is added to
arch/mips/include/uapi/asm/inst.h.

Signed-off-by: Miodrag Dinic <miodrag.dinic@imgtec.com>
Signed-off-by: Aleksandar Markovic <aleksandar.markovic@imgtech.com>
Cc: James.Hogan@imgtec.com
Cc: Paul.Burton@imgtec.com
Cc: Raghu.Gandham@imgtec.com
Cc: Leonid.Yegoshin@imgtec.com
Cc: Douglas.Leung@imgtec.com
Cc: Petar.Jovanovic@imgtec.com
Cc: Goran.Ferenc@imgtec.com
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/16511/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Miodrag Dinic 2017-06-19 17:50:11 +02:00 коммит произвёл Ralf Baechle
Родитель 3daf281f2c
Коммит 3f88ec6333
2 изменённых файлов: 115 добавлений и 78 удалений

Просмотреть файл

@ -762,6 +762,16 @@ struct msa_mi10_format { /* MSA MI10 */
;))))))
};
struct dsp_format { /* SPEC3 DSP format instructions */
__BITFIELD_FIELD(unsigned int opcode : 6,
__BITFIELD_FIELD(unsigned int base : 5,
__BITFIELD_FIELD(unsigned int index : 5,
__BITFIELD_FIELD(unsigned int rd : 5,
__BITFIELD_FIELD(unsigned int op : 5,
__BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct spec3_format { /* SPEC3 */
__BITFIELD_FIELD(unsigned int opcode:6,
__BITFIELD_FIELD(unsigned int rs:5,
@ -1053,6 +1063,7 @@ union mips_instruction {
struct b_format b_format;
struct ps_format ps_format;
struct v_format v_format;
struct dsp_format dsp_format;
struct spec3_format spec3_format;
struct fb_format fb_format;
struct fp0_format fp0_format;

Просмотреть файл

@ -939,12 +939,37 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* The remaining opcodes are the ones that are really of
* interest.
*/
#ifdef CONFIG_EVA
case spec3_op:
if (insn.dsp_format.func == lx_op) {
switch (insn.dsp_format.op) {
case lwx_op:
if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus;
LoadW(addr, value, res);
if (res)
goto fault;
compute_return_epc(regs);
regs->regs[insn.dsp_format.rd] = value;
break;
case lhx_op:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;
LoadHW(addr, value, res);
if (res)
goto fault;
compute_return_epc(regs);
regs->regs[insn.dsp_format.rd] = value;
break;
default:
goto sigill;
}
}
#ifdef CONFIG_EVA
else {
/*
* we can land here only from kernel accessing user memory,
* so we need to "switch" the address limit to user space, so
* address check can work properly.
* we can land here only from kernel accessing user
* memory, so we need to "switch" the address limit to
* user space, so that address check can work properly.
*/
seg = get_fs();
set_fs(USER_DS);
@ -1019,8 +1044,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
goto sigill;
}
set_fs(seg);
break;
}
#endif
break;
case lh_op:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;