From patchwork Wed Sep 25 19:07:47 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Walle X-Patchwork-Id: 277972 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 7EC272C00C4 for ; Thu, 26 Sep 2013 05:08:39 +1000 (EST) Received: from localhost ([::1]:54395 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VOuRx-0001LN-HT for incoming@patchwork.ozlabs.org; Wed, 25 Sep 2013 15:08:37 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37324) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VOuRQ-0001CY-Kk for qemu-devel@nongnu.org; Wed, 25 Sep 2013 15:08:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VOuRK-0002mj-NT for qemu-devel@nongnu.org; Wed, 25 Sep 2013 15:08:04 -0400 Received: from ssl.serverraum.org ([2a01:4f8:a0:1283::1:2]:52343) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VOuRK-0002mS-7c for qemu-devel@nongnu.org; Wed, 25 Sep 2013 15:07:58 -0400 Received: from localhost (localhost [127.0.0.1]) by ssl.serverraum.org (Postfix) with ESMTP id 689BB3F099; Wed, 25 Sep 2013 21:07:57 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at ssl.serverraum.org Received: from ssl.serverraum.org ([127.0.0.1]) by localhost (ssl.serverraum.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id sZv4luD1jhss; Wed, 25 Sep 2013 21:07:57 +0200 (CEST) Received: from thanatos.fritz.box (88-134-163-112-dynip.superkabel.de [88.134.163.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ssl.serverraum.org (Postfix) with ESMTPSA id 183123F079; Wed, 25 Sep 2013 21:07:57 +0200 (CEST) From: Michael Walle To: qemu-devel@nongnu.org Date: Wed, 25 Sep 2013 21:07:47 +0200 Message-Id: <1380136067-25345-1-git-send-email-michael@walle.cc> X-Mailer: git-send-email 1.7.10.4 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a01:4f8:a0:1283::1:2 Cc: Michael Walle Subject: [Qemu-devel] [RFC PATCH] target-lm32: stop VM on illegal or unknown instruction X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Instead of translating the instruction to a no-op, pause the VM and display a message to the user. As a side effect, this also works for instructions where the operands are only known at runtime. Signed-off-by: Michael Walle I have some doubt about the implementation of the "ill" helper. Esp. if it is allowed to call qemu_system_vmstop_request()? Maybe someone has a better idea. Richard Henderson proposed to raise EXCP_DEBUG, but that may lead to a segmentation fault within the gdbstub if it has not been initialized. Eg. running qemu without the '-s' commandline switch. --- target-lm32/helper.h | 1 + target-lm32/op_helper.c | 17 +++++++++ target-lm32/translate.c | 91 +++++++++++++++++++++++++++++++---------------- 3 files changed, 79 insertions(+), 30 deletions(-) diff --git a/target-lm32/helper.h b/target-lm32/helper.h index ad44fdf..f4442e0 100644 --- a/target-lm32/helper.h +++ b/target-lm32/helper.h @@ -13,5 +13,6 @@ DEF_HELPER_1(rcsr_im, i32, env) DEF_HELPER_1(rcsr_ip, i32, env) DEF_HELPER_1(rcsr_jtx, i32, env) DEF_HELPER_1(rcsr_jrx, i32, env) +DEF_HELPER_1(ill, void, env) #include "exec/def-helper.h" diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index 71f21d1..7189cb5 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -8,6 +8,10 @@ #include "exec/softmmu_exec.h" +#ifndef CONFIG_USER_ONLY +#include "sysemu/sysemu.h" +#endif + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu #define SHIFT 0 @@ -39,6 +43,19 @@ void HELPER(hlt)(CPULM32State *env) cpu_loop_exit(env); } +void HELPER(ill)(CPULM32State *env) +{ +#ifndef CONFIG_USER_ONLY + CPUState *cs = CPU(lm32_env_get_cpu(env)); + fprintf(stderr, "VM paused due to illegal instruction. " + "Connect a debugger or switch to the monitor console " + "to find out more.\n"); + qemu_system_vmstop_request(RUN_STATE_PAUSED); + cs->halted = 1; + raise_exception(env, EXCP_HALTED); +#endif +} + void HELPER(wcsr_bp)(CPULM32State *env, uint32_t bp, uint32_t idx) { uint32_t addr = bp & ~1; diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 5abd2aa..977b351 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -119,6 +119,12 @@ static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) tcg_temp_free_i32(tmp); } +static inline void t_gen_illegal_insn(DisasContext *dc) +{ + tcg_gen_movi_tl(cpu_pc, dc->pc); + gen_helper_ill(cpu_env); +} + static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { TranslationBlock *tb; @@ -422,6 +428,7 @@ static void dec_divu(DisasContext *dc) if (!(dc->def->features & LM32_FEATURE_DIVIDE)) { qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n"); + t_gen_illegal_insn(dc); return; } @@ -501,6 +508,7 @@ static void dec_modu(DisasContext *dc) if (!(dc->def->features & LM32_FEATURE_DIVIDE)) { qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n"); + t_gen_illegal_insn(dc); return; } @@ -524,6 +532,7 @@ static void dec_mul(DisasContext *dc) if (!(dc->def->features & LM32_FEATURE_MULTIPLY)) { qemu_log_mask(LOG_GUEST_ERROR, "hardware multiplier is not available\n"); + t_gen_illegal_insn(dc); return; } @@ -592,17 +601,18 @@ static void dec_scall(DisasContext *dc) LOG_DIS("scall\n"); } else if (dc->imm5 == 2) { LOG_DIS("break\n"); - } else { - qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode @0x%x", dc->pc); - return; } if (dc->imm5 == 7) { tcg_gen_movi_tl(cpu_pc, dc->pc); t_gen_raise_exception(dc, EXCP_SYSTEMCALL); - } else { + } else if (dc->imm5 == 2) { tcg_gen_movi_tl(cpu_pc, dc->pc); t_gen_raise_exception(dc, EXCP_BREAKPOINT); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode @0x%x", dc->pc); + t_gen_illegal_insn(dc); + return; } } @@ -678,6 +688,7 @@ static void dec_sextb(DisasContext *dc) if (!(dc->def->features & LM32_FEATURE_SIGN_EXTEND)) { qemu_log_mask(LOG_GUEST_ERROR, "hardware sign extender is not available\n"); + t_gen_illegal_insn(dc); return; } @@ -691,6 +702,7 @@ static void dec_sexth(DisasContext *dc) if (!(dc->def->features & LM32_FEATURE_SIGN_EXTEND)) { qemu_log_mask(LOG_GUEST_ERROR, "hardware sign extender is not available\n"); + t_gen_illegal_insn(dc); return; } @@ -719,6 +731,7 @@ static void dec_sl(DisasContext *dc) if (!(dc->def->features & LM32_FEATURE_SHIFT)) { qemu_log_mask(LOG_GUEST_ERROR, "hardware shifter is not available\n"); + t_gen_illegal_insn(dc); return; } @@ -740,24 +753,32 @@ static void dec_sr(DisasContext *dc) LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); } - if (!(dc->def->features & LM32_FEATURE_SHIFT)) { - if (dc->format == OP_FMT_RI) { - /* TODO: check r1 == 1 during runtime */ - } else { - if (dc->imm5 != 1) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware shifter is not available\n"); - return; - } - } - } - + /* The real CPU (w/o hardware shifter) only supports right shift by exactly + * one bit */ if (dc->format == OP_FMT_RI) { + if (!(dc->def->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) { + qemu_log_mask(LOG_GUEST_ERROR, + "hardware shifter is not available\n"); + t_gen_illegal_insn(dc); + return; + } tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); } else { - TCGv t0 = tcg_temp_new(); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(); tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); + + if (!(dc->def->features & LM32_FEATURE_SHIFT)) { + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1); + t_gen_illegal_insn(dc); + tcg_gen_br(l2); + } + + gen_set_label(l1); tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); + gen_set_label(l2); + tcg_temp_free(t0); } } @@ -770,24 +791,30 @@ static void dec_sru(DisasContext *dc) LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); } - if (!(dc->def->features & LM32_FEATURE_SHIFT)) { - if (dc->format == OP_FMT_RI) { - /* TODO: check r1 == 1 during runtime */ - } else { - if (dc->imm5 != 1) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware shifter is not available\n"); - return; - } - } - } - if (dc->format == OP_FMT_RI) { + if (!(dc->def->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) { + qemu_log_mask(LOG_GUEST_ERROR, + "hardware shifter is not available\n"); + t_gen_illegal_insn(dc); + return; + } tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); } else { - TCGv t0 = tcg_temp_new(); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + TCGv t0 = tcg_temp_local_new(); tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); + + if (!(dc->def->features & LM32_FEATURE_SHIFT)) { + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1); + t_gen_illegal_insn(dc); + tcg_gen_br(l2); + } + + gen_set_label(l1); tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); + gen_set_label(l2); + tcg_temp_free(t0); } } @@ -816,6 +843,7 @@ static void dec_user(DisasContext *dc) LOG_DIS("user"); qemu_log_mask(LOG_GUEST_ERROR, "user instruction undefined\n"); + t_gen_illegal_insn(dc); } static void dec_wcsr(DisasContext *dc) @@ -883,6 +911,7 @@ static void dec_wcsr(DisasContext *dc) if (dc->def->num_breakpoints <= no) { qemu_log_mask(LOG_GUEST_ERROR, "breakpoint #%i is not available\n", no); + t_gen_illegal_insn(dc); break; } gen_helper_wcsr_bp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no)); @@ -895,6 +924,7 @@ static void dec_wcsr(DisasContext *dc) if (dc->def->num_watchpoints <= no) { qemu_log_mask(LOG_GUEST_ERROR, "watchpoint #%i is not available\n", no); + t_gen_illegal_insn(dc); break; } gen_helper_wcsr_wp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no)); @@ -953,6 +983,7 @@ static void dec_xor(DisasContext *dc) static void dec_ill(DisasContext *dc) { qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode 0x%02x\n", dc->opcode); + t_gen_illegal_insn(dc); } typedef void (*DecoderInfo)(DisasContext *dc);