From e9a4475a3553b525bfe8cfe6e395baffe63dbc06 Mon Sep 17 00:00:00 2001 From: Fredrik Noring Date: Sat, 10 Nov 2018 12:10:00 -0500 Subject: [PATCH] target/mips: Make R5900 DMULT[U], DDIV[U], LL[D] and SC[D] user only The Linux kernel traps certain reserved instruction exceptions to emulate the corresponding instructions. QEMU plays the role of the kernel in user mode, so those traps are emulated by accepting the instructions. This change adds the function check_insn_opc_user_only to signal a reserved instruction exception for flagged CPUs in QEMU system mode. The MIPS III instructions DMULT[U], DDIV[U], LL[D] and SC[D] are not implemented in R5900 hardware. They are trapped and emulated by the Linux kernel and, accordingly, therefore QEMU user only instructions. Backports commit 96631327be14c4f54cc31f873c278d9ffedd1e00 from qemu --- qemu/target/mips/translate.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/qemu/target/mips/translate.c b/qemu/target/mips/translate.c index 75a2b16c..2dc29d19 100644 --- a/qemu/target/mips/translate.c +++ b/qemu/target/mips/translate.c @@ -2863,6 +2863,21 @@ static inline void check_dsp_r3(DisasContext *ctx) } } +/* + * The Linux kernel traps certain reserved instruction exceptions to + * emulate the corresponding instructions. QEMU is the kernel in user + * mode, so those traps are emulated by accepting the instructions. + * + * A reserved instruction exception is generated for flagged CPUs if + * QEMU runs in system mode. + */ +static inline void check_insn_opc_user_only(DisasContext *ctx, uint64_t flags) +{ +#ifndef CONFIG_USER_ONLY + check_insn_opc_removed(ctx, flags); +#endif +} + /* This code generates a "reserved instruction" exception if the CPU does not support the instruction set corresponding to flags. */ static inline void check_insn(DisasContext *ctx, uint64_t flags) @@ -23747,6 +23762,7 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_DDIV: case OPC_DDIVU: check_insn(ctx, ISA_MIPS3); + check_insn_opc_user_only(ctx, INSN_R5900); check_mips_64(ctx); gen_muldiv(ctx, op1, 0, rs, rt); break; @@ -26533,6 +26549,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat break; case OPC_LL: /* Load and stores */ check_insn(ctx, ISA_MIPS2); + check_insn_opc_user_only(ctx, INSN_R5900); /* Fallthrough */ case OPC_LWL: case OPC_LWR: @@ -26557,6 +26574,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat case OPC_SC: check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); + check_insn_opc_user_only(ctx, INSN_R5900); gen_st_cond(ctx, op, rt, rs, imm); break; case OPC_CACHE: @@ -26823,9 +26841,11 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat #if defined(TARGET_MIPS64) /* MIPS64 opcodes */ + case OPC_LLD: + check_insn_opc_user_only(ctx, INSN_R5900); + /* fall through */ case OPC_LDL: case OPC_LDR: - case OPC_LLD: check_insn_opc_removed(ctx, ISA_MIPS32R6); /* fall through */ case OPC_LWU: @@ -26846,6 +26866,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat case OPC_SCD: check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS3); + check_insn_opc_user_only(ctx, INSN_R5900); check_mips_64(ctx); gen_st_cond(ctx, op, rt, rs, imm); break;