diff --git a/qemu/aarch64.h b/qemu/aarch64.h index ad096574a4..3204f7be65 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_aarch64 #define helper_stqcx_le_parallel helper_stqcx_le_parallel_aarch64 #define helper_stqcx_be_parallel helper_stqcx_be_parallel_aarch64 +#define helper_uc_exit helper_uc_exit_aarch64 #define cpu_aarch64_init cpu_aarch64_init_aarch64 #define arm_cpu_exec_interrupt arm_cpu_exec_interrupt_aarch64 #define arm_cpu_update_virq arm_cpu_update_virq_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index cd81f540f0..c43816bc59 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_arm #define helper_stqcx_le_parallel helper_stqcx_le_parallel_arm #define helper_stqcx_be_parallel helper_stqcx_be_parallel_arm +#define helper_uc_exit helper_uc_exit_arm #define arm_cpu_exec_interrupt arm_cpu_exec_interrupt_arm #define arm_cpu_update_virq arm_cpu_update_virq_arm #define arm_cpu_update_vfiq arm_cpu_update_vfiq_arm diff --git a/qemu/include/exec/translator.h b/qemu/include/exec/translator.h index a86cd75977..47cc0f575d 100644 --- a/qemu/include/exec/translator.h +++ b/qemu/include/exec/translator.h @@ -37,6 +37,7 @@ typedef enum DisasJumpType { DISAS_NEXT, DISAS_TOO_MANY, + DISAS_UC_EXIT, // Unicorn: Special disas state for exiting in the middle of tb. DISAS_NORETURN, DISAS_TARGET_0, DISAS_TARGET_1, diff --git a/qemu/m68k.h b/qemu/m68k.h index 67f94364d2..8d5281c494 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_m68k #define helper_stqcx_le_parallel helper_stqcx_le_parallel_m68k #define helper_stqcx_be_parallel helper_stqcx_be_parallel_m68k +#define helper_uc_exit helper_uc_exit_m68k #define cpu_m68k_init cpu_m68k_init_m68k #define helper_reds32 helper_reds32_m68k #define helper_redf32 helper_redf32_m68k diff --git a/qemu/mips.h b/qemu/mips.h index 9b0fa37cd0..95b52b731e 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_mips #define helper_stqcx_le_parallel helper_stqcx_le_parallel_mips #define helper_stqcx_be_parallel helper_stqcx_be_parallel_mips +#define helper_uc_exit helper_uc_exit_mips #define helper_mfc0_mvpcontrol helper_mfc0_mvpcontrol_mips #define helper_mfc0_mvpconf0 helper_mfc0_mvpconf0_mips #define helper_mfc0_mvpconf1 helper_mfc0_mvpconf1_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index ec030ff261..14d8f2c370 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_mips64 #define helper_stqcx_le_parallel helper_stqcx_le_parallel_mips64 #define helper_stqcx_be_parallel helper_stqcx_be_parallel_mips64 +#define helper_uc_exit helper_uc_exit_mips64 #define helper_mfc0_mvpcontrol helper_mfc0_mvpcontrol_mips64 #define helper_mfc0_mvpconf0 helper_mfc0_mvpconf0_mips64 #define helper_mfc0_mvpconf1 helper_mfc0_mvpconf1_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index ea8c92739c..451d3d203a 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_mips64el #define helper_stqcx_le_parallel helper_stqcx_le_parallel_mips64el #define helper_stqcx_be_parallel helper_stqcx_be_parallel_mips64el +#define helper_uc_exit helper_uc_exit_mips64el #define helper_mfc0_mvpcontrol helper_mfc0_mvpcontrol_mips64el #define helper_mfc0_mvpconf0 helper_mfc0_mvpconf0_mips64el #define helper_mfc0_mvpconf1 helper_mfc0_mvpconf1_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 1b30cbc229..fce7c63306 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_mipsel #define helper_stqcx_le_parallel helper_stqcx_le_parallel_mipsel #define helper_stqcx_be_parallel helper_stqcx_be_parallel_mipsel +#define helper_uc_exit helper_uc_exit_mipsel #define helper_mfc0_mvpcontrol helper_mfc0_mvpcontrol_mipsel #define helper_mfc0_mvpconf0 helper_mfc0_mvpconf0_mipsel #define helper_mfc0_mvpconf1 helper_mfc0_mvpconf1_mipsel diff --git a/qemu/ppc.h b/qemu/ppc.h index 9648fd2fe5..758fd4d702 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_ppc #define helper_stqcx_le_parallel helper_stqcx_le_parallel_ppc #define helper_stqcx_be_parallel helper_stqcx_be_parallel_ppc +#define helper_uc_exit helper_uc_exit_ppc #define ppc_cpu_unrealize ppc_cpu_unrealize_ppc #define ppc_cpu_instance_finalize ppc_cpu_instance_finalize_ppc #define ppc_cpu_do_interrupt ppc_cpu_do_interrupt_ppc diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 2d995d5ece..cb00e53d03 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_ppc64 #define helper_stqcx_le_parallel helper_stqcx_le_parallel_ppc64 #define helper_stqcx_be_parallel helper_stqcx_be_parallel_ppc64 +#define helper_uc_exit helper_uc_exit_ppc64 #define ppc_cpu_unrealize ppc_cpu_unrealize_ppc64 #define ppc_cpu_instance_finalize ppc_cpu_instance_finalize_ppc64 #define ppc_cpu_do_interrupt ppc_cpu_do_interrupt_ppc64 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index 26c798b413..edacb77758 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_riscv32 #define helper_stqcx_le_parallel helper_stqcx_le_parallel_riscv32 #define helper_stqcx_be_parallel helper_stqcx_be_parallel_riscv32 +#define helper_uc_exit helper_uc_exit_riscv32 #define riscv_cpu_mmu_index riscv_cpu_mmu_index_riscv32 #define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv32 #define riscv_cpu_fp_enabled riscv_cpu_fp_enabled_riscv32 @@ -1360,7 +1361,6 @@ #define helper_fclass_d helper_fclass_d_riscv32 #define riscv_raise_exception riscv_raise_exception_riscv32 #define helper_raise_exception helper_raise_exception_riscv32 -#define helper_uc_riscv_exit helper_uc_riscv_exit_riscv32 #define helper_csrrw helper_csrrw_riscv32 #define helper_csrrs helper_csrrs_riscv32 #define helper_csrrc helper_csrrc_riscv32 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index 8332ce6dab..ec9c1f814f 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_riscv64 #define helper_stqcx_le_parallel helper_stqcx_le_parallel_riscv64 #define helper_stqcx_be_parallel helper_stqcx_be_parallel_riscv64 +#define helper_uc_exit helper_uc_exit_riscv64 #define riscv_cpu_mmu_index riscv_cpu_mmu_index_riscv64 #define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv64 #define riscv_cpu_fp_enabled riscv_cpu_fp_enabled_riscv64 @@ -1360,7 +1361,6 @@ #define helper_fclass_d helper_fclass_d_riscv64 #define riscv_raise_exception riscv_raise_exception_riscv64 #define helper_raise_exception helper_raise_exception_riscv64 -#define helper_uc_riscv_exit helper_uc_riscv_exit_riscv64 #define helper_csrrw helper_csrrw_riscv64 #define helper_csrrs helper_csrrs_riscv64 #define helper_csrrc helper_csrrc_riscv64 diff --git a/qemu/s390x.h b/qemu/s390x.h index 5daa819afa..22811e0d7a 100644 --- a/qemu/s390x.h +++ b/qemu/s390x.h @@ -1294,7 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_s390x #define helper_stqcx_le_parallel helper_stqcx_le_parallel_s390x #define helper_stqcx_be_parallel helper_stqcx_be_parallel_s390x -#define helper_uc_s390x_exit helper_uc_s390x_exit_s390x +#define helper_uc_exit helper_uc_exit_s390x #define tcg_s390_tod_updated tcg_s390_tod_updated_s390x #define tcg_s390_program_interrupt tcg_s390_program_interrupt_s390x #define tcg_s390_data_exception tcg_s390_data_exception_s390x diff --git a/qemu/sparc.h b/qemu/sparc.h index 5f7c4689b7..8aac8b2bc3 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_sparc #define helper_stqcx_le_parallel helper_stqcx_le_parallel_sparc #define helper_stqcx_be_parallel helper_stqcx_be_parallel_sparc +#define helper_uc_exit helper_uc_exit_sparc #define helper_compute_psr helper_compute_psr_sparc #define helper_compute_C_icc helper_compute_C_icc_sparc #define cpu_sparc_set_id cpu_sparc_set_id_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 33003493db..cb99c50f86 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_sparc64 #define helper_stqcx_le_parallel helper_stqcx_le_parallel_sparc64 #define helper_stqcx_be_parallel helper_stqcx_be_parallel_sparc64 +#define helper_uc_exit helper_uc_exit_sparc64 #define helper_compute_psr helper_compute_psr_sparc64 #define helper_compute_C_icc helper_compute_C_icc_sparc64 #define cpu_sparc_set_id cpu_sparc_set_id_sparc64 diff --git a/qemu/target/arm/helper.h b/qemu/target/arm/helper.h index 616d032c84..8b91b6d2cf 100644 --- a/qemu/target/arm/helper.h +++ b/qemu/target/arm/helper.h @@ -1,5 +1,6 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) +DEF_HELPER_1(uc_exit, void, env) DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_NO_RWG_SE, i32, i32) diff --git a/qemu/target/arm/op_helper.c b/qemu/target/arm/op_helper.c index af4e1089c4..18fa56250b 100644 --- a/qemu/target/arm/op_helper.c +++ b/qemu/target/arm/op_helper.c @@ -998,3 +998,12 @@ uint32_t HELPER(uc_hooksys64)(CPUARMState *env, uint32_t insn, void *hk) JIT_CALLBACK_GUARD_VAR(ret, ((uc_cb_insn_sys_t)(hook->callback))(uc, uc_rt, &cp_reg, hook->user_data)); return ret; } + +void HELPER(uc_exit)(CPUARMState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); +} \ No newline at end of file diff --git a/qemu/target/arm/translate-a64.c b/qemu/target/arm/translate-a64.c index 922976536e..53a6d87f34 100644 --- a/qemu/target/arm/translate-a64.c +++ b/qemu/target/arm/translate-a64.c @@ -14737,7 +14737,7 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(dc->uc, dcbase->pc_next)) { // imitate WFI instruction to halt emulation - dcbase->is_jmp = DISAS_WFI; + dcbase->is_jmp = DISAS_UC_EXIT; } else { if (dc->ss_active && !dc->pstate_ss) { /* Singlestep state is Active-pending. @@ -14830,6 +14830,12 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_exit_tb(tcg_ctx, NULL, 0); break; } + case DISAS_UC_EXIT: + { + gen_a64_set_pc_im(tcg_ctx, dc->base.pc_next); + gen_helper_uc_exit(tcg_ctx, tcg_ctx->cpu_env); + break; + } } } } diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 744d8ff709..9058895ee0 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -11462,34 +11462,35 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(dc->uc, dcbase->pc_next)) { // imitate WFI instruction to halt emulation - dcbase->is_jmp = DISAS_WFI; - } else { - dc->pc_curr = dc->base.pc_next; - insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b); - dc->insn = insn; - - // Unicorn: - // - // If we get an error during fetching code, we have to skip the instruction decoding - // to ensure the PC remains unchanged. - // - // This is to keep the same behavior with Unicorn1, though, it's inconsistent with - // official arm documents. - // - // See discussion here: https://github.com/unicorn-engine/unicorn/issues/1536 - if (dc->uc->invalid_error) { - dcbase->is_jmp = DISAS_WFI; - return; - } + dcbase->is_jmp = DISAS_UC_EXIT; + return; + } + + dc->pc_curr = dc->base.pc_next; + insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b); + dc->insn = insn; + + // Unicorn: + // + // If we get an error during fetching code, we have to skip the instruction decoding + // to ensure the PC remains unchanged. + // + // This is to keep the same behavior with Unicorn1, though, it's inconsistent with + // official arm documents. + // + // See discussion here: https://github.com/unicorn-engine/unicorn/issues/1536 + if (dc->uc->invalid_error) { + dcbase->is_jmp = DISAS_UC_EXIT; + return; + } - dc->base.pc_next += 4; - disas_arm_insn(dc, insn); + dc->base.pc_next += 4; + disas_arm_insn(dc, insn); - arm_post_translate_insn(dc); + arm_post_translate_insn(dc); - /* ARM is a fixed-length ISA. We performed the cross-page check - in init_disas_context by adjusting max_insns. */ - } + /* ARM is a fixed-length ISA. We performed the cross-page check + in init_disas_context by adjusting max_insns. */ } static bool thumb_insn_is_unconditional(DisasContext *s, uint32_t insn) @@ -11555,7 +11556,7 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(uc, dcbase->pc_next)) { // imitate WFI instruction to halt emulation - dcbase->is_jmp = DISAS_WFI; + dcbase->is_jmp = DISAS_UC_EXIT; return; } @@ -11753,6 +11754,12 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_SMC: gen_exception(tcg_ctx, EXCP_SMC, syn_aa32_smc(), 3); break; + case DISAS_UC_EXIT: + { + gen_set_pc_im(dc, dc->base.pc_next); + gen_helper_uc_exit(tcg_ctx, tcg_ctx->cpu_env); + break; + } } } diff --git a/qemu/target/i386/helper.h b/qemu/target/i386/helper.h index 399cc0df99..7237b0b448 100644 --- a/qemu/target/i386/helper.h +++ b/qemu/target/i386/helper.h @@ -1,5 +1,6 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) +DEF_HELPER_1(uc_exit, void, env) DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) diff --git a/qemu/target/i386/misc_helper.c b/qemu/target/i386/misc_helper.c index ccc12c8192..a96f397c5c 100644 --- a/qemu/target/i386/misc_helper.c +++ b/qemu/target/i386/misc_helper.c @@ -732,3 +732,12 @@ void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val) env->pkru = val; tlb_flush(cs); } + +void helper_uc_exit(CPUX86State *env) +{ + X86CPU *cpu = env_archcpu(env); + + cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC()); + + do_hlt(cpu); +} \ No newline at end of file diff --git a/qemu/target/i386/translate.c b/qemu/target/i386/translate.c index 8278774a58..d6232c4c7c 100644 --- a/qemu/target/i386/translate.c +++ b/qemu/target/i386/translate.c @@ -4803,16 +4803,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) s->uc = env->uc; - // Unicorn: end address tells us to stop emulation - if (uc_addr_is_exit(env->uc, s->pc)) { - // imitate the HLT instruction - gen_update_cc_op(s); - gen_sync_pc(tcg_ctx, pc_start - s->cs_base); - gen_helper_hlt(tcg_ctx, tcg_ctx->cpu_env, tcg_const_i32(tcg_ctx, s->pc - pc_start)); - s->base.is_jmp = DISAS_NORETURN; - return s->pc; - } - // Unicorn: callback might need to access to EFLAGS, // or want to stop emulation immediately if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) { @@ -9385,6 +9375,12 @@ static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) DisasContext *dc = container_of(dcbase, DisasContext, base); target_ulong pc_next; + // Unicorn: end address tells us to stop emulation + if (uc_addr_is_exit(((CPUX86State *)cpu->env_ptr)->uc, dcbase->pc_next)) { + dc->base.is_jmp = DISAS_UC_EXIT; + return; + } + pc_next = disas_insn(dc, cpu); if (dc->tf || (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) { @@ -9416,10 +9412,21 @@ static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); + TCGContext *tcg_ctx = dc->uc->tcg_ctx; - if (dc->base.is_jmp == DISAS_TOO_MANY) { + switch (dc->base.is_jmp) { + case DISAS_TOO_MANY: gen_jmp_im(dc, dc->base.pc_next - dc->cs_base); gen_eob(dc); + break; + case DISAS_UC_EXIT: + // imitate the HLT instruction + gen_update_cc_op(dc); + gen_jmp_im(dc, dc->base.pc_next - dc->cs_base); + gen_helper_uc_exit(tcg_ctx, tcg_ctx->cpu_env); + break; + default: + break; // suppress compiler warnings } } diff --git a/qemu/target/m68k/translate.c b/qemu/target/m68k/translate.c index 5b9a74ce2b..d1948f3ed0 100644 --- a/qemu/target/m68k/translate.c +++ b/qemu/target/m68k/translate.c @@ -6325,7 +6325,7 @@ static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(uc, dc->pc)) { - gen_exception(dc, dc->pc, EXCP_HLT); + dc->base.is_jmp = DISAS_UC_EXIT; return; } @@ -6407,6 +6407,9 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_exit_tb(tcg_ctx, NULL, 0); } break; + case DISAS_UC_EXIT: + gen_exception(dc, dc->pc, EXCP_HLT); + break; default: g_assert_not_reached(); } diff --git a/qemu/target/mips/helper.h b/qemu/target/mips/helper.h index 221e78257b..d9d31ff6ef 100644 --- a/qemu/target/mips/helper.h +++ b/qemu/target/mips/helper.h @@ -1,5 +1,6 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) +DEF_HELPER_1(uc_exit, void, env) DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) DEF_HELPER_2(raise_exception, noreturn, env, i32) diff --git a/qemu/target/mips/op_helper.c b/qemu/target/mips/op_helper.c index 9802b9cebd..ead23fc1d5 100644 --- a/qemu/target/mips/op_helper.c +++ b/qemu/target/mips/op_helper.c @@ -1076,6 +1076,19 @@ void helper_wait(CPUMIPSState *env) raise_exception(env, EXCP_HLT); } +void helper_uc_exit(CPUMIPSState *env) +{ + CPUState *cs = env_cpu(env); + + cs->halted = 1; + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); + /* + * Last instruction in the block, PC was updated before + * - no need to recover PC and icount. + */ + raise_exception(env, EXCP_HLT); +} + void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) diff --git a/qemu/target/mips/translate.c b/qemu/target/mips/translate.c index 3fab57b251..40b280a44a 100644 --- a/qemu/target/mips/translate.c +++ b/qemu/target/mips/translate.c @@ -30942,9 +30942,7 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(uc, ctx->base.pc_next)) { - // raise a special interrupt to quit - gen_helper_wait(tcg_ctx, tcg_ctx->cpu_env); - ctx->base.is_jmp = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_UC_EXIT; return; } @@ -31053,7 +31051,7 @@ static void mips_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) DisasContext *ctx = container_of(dcbase, DisasContext, base); TCGContext *tcg_ctx = ctx->uc->tcg_ctx; - if (ctx->base.singlestep_enabled && ctx->base.is_jmp != DISAS_NORETURN) { + if (ctx->base.singlestep_enabled && (ctx->base.is_jmp == DISAS_NORETURN || ctx->base.is_jmp == DISAS_UC_EXIT)) { save_cpu_state(ctx, ctx->base.is_jmp != DISAS_EXIT); gen_helper_raise_exception_debug(tcg_ctx, tcg_ctx->cpu_env); } else { @@ -31072,6 +31070,9 @@ static void mips_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) break; case DISAS_NORETURN: break; + case DISAS_UC_EXIT: + gen_helper_uc_exit(tcg_ctx, tcg_ctx->cpu_env); + break; default: g_assert_not_reached(); } diff --git a/qemu/target/ppc/translate.c b/qemu/target/ppc/translate.c index 0b3e5c8c08..cac155fe33 100644 --- a/qemu/target/ppc/translate.c +++ b/qemu/target/ppc/translate.c @@ -3727,6 +3727,22 @@ static void gen_wait(DisasContext *ctx) gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); } +static void gen_uc_exit(DisasContext *ctx) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv_i32 t0 = tcg_const_i32(tcg_ctx, 1); +#ifdef _MSC_VER + tcg_gen_st_i32(tcg_ctx, t0, tcg_ctx->cpu_env, + 0 - offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); +#else + tcg_gen_st_i32(tcg_ctx, t0, tcg_ctx->cpu_env, + -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); +#endif + tcg_temp_free_i32(tcg_ctx, t0); + /* Stop translation, as the CPU is supposed to sleep from now */ + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); +} + #if defined(TARGET_PPC64) static void gen_doze(DisasContext *ctx) { @@ -7627,8 +7643,7 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(uc, ctx->base.pc_next)) { - gen_wait(ctx); - dcbase->is_jmp = DISAS_NORETURN; + dcbase->is_jmp = DISAS_UC_EXIT; return; } @@ -7720,6 +7735,10 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) DisasContext *ctx = container_of(dcbase, DisasContext, base); TCGContext *tcg_ctx = cs->uc->tcg_ctx; + if (dcbase->is_jmp == DISAS_UC_EXIT) { + gen_uc_exit(ctx); + return; + } if (ctx->exception == POWERPC_EXCP_NONE) { gen_goto_tb(ctx, 0, ctx->base.pc_next); diff --git a/qemu/target/riscv/helper.h b/qemu/target/riscv/helper.h index 32e483860f..87e3c20b4c 100644 --- a/qemu/target/riscv/helper.h +++ b/qemu/target/riscv/helper.h @@ -1,6 +1,6 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) -DEF_HELPER_1(uc_riscv_exit, void, env) +DEF_HELPER_1(uc_exit, void, env) /* Exceptions */ DEF_HELPER_2(raise_exception, noreturn, env, i32) diff --git a/qemu/target/riscv/op_helper.c b/qemu/target/riscv/op_helper.c index 5afb2ce881..ea149482d6 100644 --- a/qemu/target/riscv/op_helper.c +++ b/qemu/target/riscv/op_helper.c @@ -202,7 +202,7 @@ void helper_tlb_flush(CPURISCVState *env) } } -void helper_uc_riscv_exit(CPURISCVState *env) +void helper_uc_exit(CPURISCVState *env) { CPUState *cs = env_cpu(env); diff --git a/qemu/target/riscv/translate.c b/qemu/target/riscv/translate.c index 792bc12fd0..e7e8c80238 100644 --- a/qemu/target/riscv/translate.c +++ b/qemu/target/riscv/translate.c @@ -34,11 +34,6 @@ #include "exec/gen-icount.h" -/* - * Unicorn: Special disas state for exiting in the middle of tb. - */ -#define DISAS_UC_EXIT DISAS_TARGET_6 - typedef struct DisasContext { DisasContextBase base; /* pc_succ_insn points to the instruction following base.pc_next */ @@ -912,7 +907,7 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) break; case DISAS_UC_EXIT: tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->base.pc_next); - gen_helper_uc_riscv_exit(ctx->uc->tcg_ctx, ctx->uc->tcg_ctx->cpu_env); + gen_helper_uc_exit(ctx->uc->tcg_ctx, ctx->uc->tcg_ctx->cpu_env); break; default: g_assert_not_reached(); diff --git a/qemu/target/s390x/excp_helper.c b/qemu/target/s390x/excp_helper.c index a91c407c9e..917505eed7 100644 --- a/qemu/target/s390x/excp_helper.c +++ b/qemu/target/s390x/excp_helper.c @@ -599,7 +599,7 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr); } -void helper_uc_s390x_exit(CPUS390XState *env) +void helper_uc_exit(CPUS390XState *env) { CPUState *cs = env_cpu(env); diff --git a/qemu/target/s390x/helper.h b/qemu/target/s390x/helper.h index abd8dd2a97..0549a2b5aa 100644 --- a/qemu/target/s390x/helper.h +++ b/qemu/target/s390x/helper.h @@ -1,6 +1,6 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) -DEF_HELPER_1(uc_s390x_exit, void, env) +DEF_HELPER_1(uc_exit, void, env) DEF_HELPER_2(exception, noreturn, env, i32) DEF_HELPER_2(data_exception, noreturn, env, i32) diff --git a/qemu/target/s390x/translate.c b/qemu/target/s390x/translate.c index e41a3b73b0..b0834f3ec9 100644 --- a/qemu/target/s390x/translate.c +++ b/qemu/target/s390x/translate.c @@ -1203,8 +1203,6 @@ typedef struct { /* We are exiting the TB to the main loop. */ #define DISAS_PC_STALE_NOCHAIN DISAS_TARGET_4 -#define DISAS_UNICORN_HALT DISAS_TARGET_11 - /* Instruction flags */ #define IF_AFP1 0x0001 /* r1 is a fp reg for HFP/FPS instructions */ #define IF_AFP2 0x0002 /* r2 is a fp reg for HFP/FPS instructions */ @@ -6882,7 +6880,8 @@ static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(dc->uc, dcbase->pc_next)) { // imitate PGM exception to halt emulation - dcbase->is_jmp = DISAS_UNICORN_HALT; + dcbase->is_jmp = DISAS_UC_EXIT; + return; } else { dc->base.is_jmp = translate_one(env, dc); if (dc->base.is_jmp == DISAS_NEXT) { @@ -6902,11 +6901,11 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) TCGContext *tcg_ctx = dc->uc->tcg_ctx; switch (dc->base.is_jmp) { - case DISAS_UNICORN_HALT: + case DISAS_UC_EXIT: tcg_gen_insn_start(tcg_ctx, dc->base.pc_next, 0, 0); update_psw_addr(dc); update_cc_op(dc); - gen_helper_uc_s390x_exit(tcg_ctx, tcg_ctx->cpu_env); + gen_helper_uc_exit(tcg_ctx, tcg_ctx->cpu_env); break; case DISAS_GOTO_TB: case DISAS_NORETURN: diff --git a/qemu/target/sparc/helper.c b/qemu/target/sparc/helper.c index bb8687437a..fd838cb25b 100644 --- a/qemu/target/sparc/helper.c +++ b/qemu/target/sparc/helper.c @@ -244,4 +244,15 @@ void helper_power_down(CPUSPARCState *env) env->npc = env->pc + 4; cpu_loop_exit(cs); } -#endif + +void helper_uc_exit(CPUSPARCState *env) +{ + CPUState *cs = env_cpu(env); + + cs->halted = 1; + cs->exception_index = EXCP_HLT; + env->pc = env->npc; + env->npc = env->pc + 4; + cpu_loop_exit(cs); +} +#endif \ No newline at end of file diff --git a/qemu/target/sparc/helper.h b/qemu/target/sparc/helper.h index 69924307ee..4179da45bd 100644 --- a/qemu/target/sparc/helper.h +++ b/qemu/target/sparc/helper.h @@ -6,6 +6,7 @@ DEF_HELPER_1(rett, void, env) DEF_HELPER_2(wrpsr, void, env, tl) DEF_HELPER_1(rdpsr, tl, env) DEF_HELPER_1(power_down, void, env) +DEF_HELPER_1(uc_exit, void, env) #else DEF_HELPER_FLAGS_2(wrpil, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_2(wrgl, void, env, tl) diff --git a/qemu/target/sparc/translate.c b/qemu/target/sparc/translate.c index 95b24ab649..5dc5c6760d 100644 --- a/qemu/target/sparc/translate.c +++ b/qemu/target/sparc/translate.c @@ -5952,10 +5952,7 @@ static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) // Unicorn: end address tells us to stop emulation if (uc_addr_is_exit(uc, dc->pc)) { -#ifndef TARGET_SPARC64 - gen_helper_power_down(tcg_ctx, tcg_ctx->cpu_env); -#endif - dcbase->is_jmp = DISAS_NORETURN; + dcbase->is_jmp = DISAS_UC_EXIT; return; } @@ -6012,6 +6009,12 @@ static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) save_state(dc); tcg_gen_exit_tb(tcg_ctx, NULL, 0); break; + + case DISAS_UC_EXIT: + #ifndef TARGET_SPARC64 + gen_helper_uc_exit(tcg_ctx, tcg_ctx->cpu_env); + #endif + break; default: g_assert_not_reached(); diff --git a/qemu/target/tricore/helper.h b/qemu/target/tricore/helper.h index e0712597d9..efc20c06ae 100644 --- a/qemu/target/tricore/helper.h +++ b/qemu/target/tricore/helper.h @@ -22,7 +22,7 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) -DEF_HELPER_1(uc_tricore_exit,void, env) +DEF_HELPER_1(uc_exit, void, env) /* Arithmetic */ DEF_HELPER_3(add_ssov, i32, env, i32, i32) diff --git a/qemu/target/tricore/op_helper.c b/qemu/target/tricore/op_helper.c index 6bb7b3a028..dc1d56c0aa 100644 --- a/qemu/target/tricore/op_helper.c +++ b/qemu/target/tricore/op_helper.c @@ -2794,7 +2794,7 @@ uint32_t helper_psw_read(CPUTriCoreState *env) return psw_read(env); } -void helper_uc_tricore_exit(CPUTriCoreState *env) +void helper_uc_exit(CPUTriCoreState *env) { CPUState *cs = env_cpu(env); diff --git a/qemu/target/tricore/translate.c b/qemu/target/tricore/translate.c index 75188b8be6..d26842372c 100644 --- a/qemu/target/tricore/translate.c +++ b/qemu/target/tricore/translate.c @@ -33,11 +33,6 @@ #include "exec/translator.h" #include "exec/gen-icount.h" -/* - * Unicorn: Special disas state for exiting in the middle of tb. - */ -#define DISAS_UC_EXIT DISAS_TARGET_6 - static const char *regnames_a[] = { "a0" , "a1" , "a2" , "a3" , "a4" , "a5" , "a6" , "a7" , "a8" , "a9" , "sp" , "a11" , @@ -9287,8 +9282,7 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) gen_goto_tb(ctx, 0, ctx->base.pc_next); break; case DISAS_UC_EXIT: - gen_save_pc(ctx, ctx->base.pc_next); - gen_helper_uc_tricore_exit(ctx->uc->tcg_ctx, ctx->uc->tcg_ctx->cpu_env); + gen_helper_uc_exit(ctx->uc->tcg_ctx, ctx->uc->tcg_ctx->cpu_env); break; case DISAS_NORETURN: break; diff --git a/qemu/tricore.h b/qemu/tricore.h index 937eb5d257..4cfcf7708b 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_tricore #define helper_stqcx_le_parallel helper_stqcx_le_parallel_tricore #define helper_stqcx_be_parallel helper_stqcx_be_parallel_tricore +#define helper_uc_exit helper_uc_exit_tricore #define helper_fadd helper_fadd_tricore #define helper_fsub helper_fsub_tricore #define helper_fmul helper_fmul_tricore @@ -1303,5 +1304,4 @@ #define helper_pack helper_pack_tricore #define gen_intermediate_code gen_intermediate_code_tricore #define restore_state_to_opc restore_state_to_opc_tricore -#define helper_uc_tricore_exit helper_uc_tricore_exit_tricore #endif diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 637b88524a..ff8ad359e7 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -1294,6 +1294,7 @@ #define tlb_reset_dirty_by_vaddr tlb_reset_dirty_by_vaddr_x86_64 #define helper_stqcx_le_parallel helper_stqcx_le_parallel_x86_64 #define helper_stqcx_be_parallel helper_stqcx_be_parallel_x86_64 +#define helper_uc_exit helper_uc_exit_x86_64 #define cpu_get_tsc cpu_get_tsc_x86_64 #define x86_cpu_get_memory_mapping x86_cpu_get_memory_mapping_x86_64 #define cpu_x86_update_dr7 cpu_x86_update_dr7_x86_64 diff --git a/symbols.sh b/symbols.sh index bcedaea983..f896ef72fd 100755 --- a/symbols.sh +++ b/symbols.sh @@ -1294,6 +1294,7 @@ gen_helper_cpsr_write \ tlb_reset_dirty_by_vaddr \ helper_stqcx_le_parallel \ helper_stqcx_be_parallel \ +helper_uc_exit \ " x86_64_SYMBOLS=" @@ -4375,7 +4376,6 @@ helper_fcvt_d_wu \ helper_fclass_d \ riscv_raise_exception \ helper_raise_exception \ -helper_uc_riscv_exit \ helper_csrrw \ helper_csrrs \ helper_csrrc \ @@ -6533,8 +6533,7 @@ do_store_fpscr ppc64_SYMBOLS=${ppc_SYMBOLS} -s390x_SYMBOLS="helper_uc_s390x_exit \ -tcg_s390_tod_updated \ +s390x_SYMBOLS="tcg_s390_tod_updated \ tcg_s390_program_interrupt \ tcg_s390_data_exception \ " @@ -6549,7 +6548,6 @@ helper_fmsub \ helper_pack \ gen_intermediate_code \ restore_state_to_opc \ -helper_uc_tricore_exit \ " ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore"