mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-02 05:30:59 +00:00
target-i386: Handle I/O breakpoints
Backports commit 5223a9423c5fb9e32b0c3eaaa2c0bf8c5cfd6866 from qemu
This commit is contained in:
parent
d1cfcb6d79
commit
c6bfe2a03d
|
@ -48,68 +48,81 @@ static inline int hw_breakpoint_len(unsigned long dr7, int index)
|
|||
return (len == 2) ? 8 : len + 1;
|
||||
}
|
||||
|
||||
static void hw_breakpoint_insert(CPUX86State *env, int index)
|
||||
static int hw_breakpoint_insert(CPUX86State *env, int index)
|
||||
{
|
||||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||
int type = 0, err = 0;
|
||||
target_ulong dr7 = env->dr[7];
|
||||
target_ulong drN = env->dr[index];
|
||||
int err = 0;
|
||||
|
||||
switch (hw_breakpoint_type(env->dr[7], index)) {
|
||||
switch (hw_breakpoint_type(dr7, index)) {
|
||||
case DR7_TYPE_BP_INST:
|
||||
if (hw_breakpoint_enabled(env->dr[7], index)) {
|
||||
err = cpu_breakpoint_insert(cs, env->dr[index], BP_CPU,
|
||||
if (hw_breakpoint_enabled(dr7, index)) {
|
||||
err = cpu_breakpoint_insert(cs, drN, BP_CPU,
|
||||
&env->cpu_breakpoint[index]);
|
||||
}
|
||||
break;
|
||||
case DR7_TYPE_DATA_WR:
|
||||
type = BP_CPU | BP_MEM_WRITE;
|
||||
break;
|
||||
|
||||
case DR7_TYPE_IO_RW:
|
||||
/* No support for I/O watchpoints yet */
|
||||
/* Notice when we should enable calls to bpt_io. */
|
||||
return hw_breakpoint_enabled(env->dr[7], index)
|
||||
? HF_IOBPT_MASK : 0;
|
||||
|
||||
case DR7_TYPE_DATA_WR:
|
||||
if (hw_breakpoint_enabled(dr7, index)) {
|
||||
err = cpu_watchpoint_insert(cs, drN,
|
||||
hw_breakpoint_len(dr7, index),
|
||||
BP_CPU | BP_MEM_WRITE,
|
||||
&env->cpu_watchpoint[index]);
|
||||
}
|
||||
break;
|
||||
|
||||
case DR7_TYPE_DATA_RW:
|
||||
type = BP_CPU | BP_MEM_ACCESS;
|
||||
if (hw_breakpoint_enabled(dr7, index)) {
|
||||
err = cpu_watchpoint_insert(cs, drN,
|
||||
hw_breakpoint_len(dr7, index),
|
||||
BP_CPU | BP_MEM_ACCESS,
|
||||
&env->cpu_watchpoint[index]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != 0) {
|
||||
err = cpu_watchpoint_insert(cs, env->dr[index],
|
||||
hw_breakpoint_len(env->dr[7], index),
|
||||
type, &env->cpu_watchpoint[index]);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
env->cpu_breakpoint[index] = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hw_breakpoint_remove(CPUX86State *env, int index)
|
||||
{
|
||||
CPUState *cs;
|
||||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||
|
||||
if (!env->cpu_breakpoint[index]) {
|
||||
return;
|
||||
}
|
||||
cs = CPU(x86_env_get_cpu(env));
|
||||
switch (hw_breakpoint_type(env->dr[7], index)) {
|
||||
case DR7_TYPE_BP_INST:
|
||||
if (hw_breakpoint_enabled(env->dr[7], index)) {
|
||||
if (env->cpu_breakpoint[index]) {
|
||||
cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
|
||||
env->cpu_breakpoint[index] = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case DR7_TYPE_DATA_WR:
|
||||
case DR7_TYPE_DATA_RW:
|
||||
cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
|
||||
if (env->cpu_breakpoint[index]) {
|
||||
cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
|
||||
env->cpu_breakpoint[index] = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case DR7_TYPE_IO_RW:
|
||||
/* No support for I/O watchpoints yet */
|
||||
/* HF_IOBPT_MASK cleared elsewhere. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7)
|
||||
{
|
||||
int i;
|
||||
target_ulong old_dr7 = env->dr[7];
|
||||
int iobpt = 0;
|
||||
int i;
|
||||
|
||||
new_dr7 |= DR7_FIXED_1;
|
||||
|
||||
|
@ -123,7 +136,10 @@ void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7)
|
|||
|
||||
for (i = 0; i < DR7_MAX_BP; i++) {
|
||||
if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) {
|
||||
hw_breakpoint_remove(env, i);
|
||||
iobpt |= hw_breakpoint_insert(env, i);
|
||||
} else if (hw_breakpoint_type(new_dr7, i) == DR7_TYPE_IO_RW
|
||||
&& hw_breakpoint_enabled(new_dr7, i)) {
|
||||
iobpt |= HF_IOBPT_MASK;
|
||||
}
|
||||
}
|
||||
env->dr[7] = new_dr7;
|
||||
|
@ -138,9 +154,11 @@ void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7)
|
|||
}
|
||||
env->dr[7] = new_dr7;
|
||||
for (i = 0; i < DR7_MAX_BP; i++) {
|
||||
hw_breakpoint_insert(env, i);
|
||||
iobpt |= hw_breakpoint_insert(env, i);
|
||||
}
|
||||
}
|
||||
|
||||
env->hflags = (env->hflags & ~HF_IOBPT_MASK) | iobpt;
|
||||
}
|
||||
|
||||
static bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
|
||||
|
@ -242,3 +260,30 @@ void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if Port I/O is trapped by a breakpoint. */
|
||||
void helper_bpt_io(CPUX86State *env, uint32_t port,
|
||||
uint32_t size, target_ulong next_eip)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
target_ulong dr7 = env->dr[7];
|
||||
int i, hit = 0;
|
||||
|
||||
for (i = 0; i < DR7_MAX_BP; ++i) {
|
||||
if (hw_breakpoint_type(dr7, i) == DR7_TYPE_IO_RW
|
||||
&& hw_breakpoint_enabled(dr7, i)) {
|
||||
int bpt_len = hw_breakpoint_len(dr7, i);
|
||||
if (port + size - 1 >= env->dr[i]
|
||||
&& port <= env->dr[i] + bpt_len - 1) {
|
||||
hit |= 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
env->dr[6] = (env->dr[6] & ~0xf) | hit;
|
||||
env->eip = next_eip;
|
||||
raise_exception(env, EXCP01_DB);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@
|
|||
#define HF_SVMI_SHIFT 21 /* SVM intercepts are active */
|
||||
#define HF_OSFXSR_SHIFT 22 /* CR4.OSFXSR */
|
||||
#define HF_SMAP_SHIFT 23 /* CR4.SMAP */
|
||||
#define HF_IOBPT_SHIFT 24 /* an io breakpoint enabled */
|
||||
|
||||
#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
|
||||
#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
|
||||
|
@ -179,6 +180,7 @@
|
|||
#define HF_SVMI_MASK (1 << HF_SVMI_SHIFT)
|
||||
#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)
|
||||
#define HF_SMAP_MASK (1 << HF_SMAP_SHIFT)
|
||||
#define HF_IOBPT_MASK (1 << HF_IOBPT_SHIFT)
|
||||
|
||||
/* hflags2 */
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ DEF_HELPER_3(outw, void, env, i32, i32)
|
|||
DEF_HELPER_2(inw, tl, env, i32)
|
||||
DEF_HELPER_3(outl, void, env, i32, i32)
|
||||
DEF_HELPER_2(inl, tl, env, i32)
|
||||
DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
|
||||
|
||||
DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64)
|
||||
DEF_HELPER_3(vmexit, void, env, i32, i64)
|
||||
|
|
|
@ -1364,6 +1364,20 @@ static inline void gen_cmps(DisasContext *s, TCGMemOp ot)
|
|||
gen_op_add_reg_T0(tcg_ctx, s->aflag, R_EDI);
|
||||
}
|
||||
|
||||
static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
|
||||
if (s->flags & HF_IOBPT_MASK) {
|
||||
TCGv_i32 t_size = tcg_const_i32(tcg_ctx, 1 << ot);
|
||||
TCGv t_next = tcg_const_tl(tcg_ctx, s->pc - s->cs_base);
|
||||
|
||||
gen_helper_bpt_io(tcg_ctx, tcg_ctx->cpu_env, t_port, t_size, t_next);
|
||||
tcg_temp_free_i32(tcg_ctx, t_size);
|
||||
tcg_temp_free(tcg_ctx, t_next);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_ins(DisasContext *s, TCGMemOp ot)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
|
@ -1383,6 +1397,7 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot)
|
|||
gen_op_st_v(s, ot, *cpu_T[0], cpu_A0);
|
||||
gen_op_movl_T0_Dshift(tcg_ctx, ot);
|
||||
gen_op_add_reg_T0(tcg_ctx, s->aflag, R_EDI);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
}
|
||||
|
||||
static inline void gen_outs(DisasContext *s, TCGMemOp ot)
|
||||
|
@ -1404,6 +1419,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot)
|
|||
|
||||
gen_op_movl_T0_Dshift(tcg_ctx, ot);
|
||||
gen_op_add_reg_T0(tcg_ctx, s->aflag, R_ESI);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
}
|
||||
|
||||
/* same method as Valgrind : we generate jumps to current or next
|
||||
|
@ -6952,6 +6968,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
tcg_gen_movi_i32(tcg_ctx, cpu_tmp2_i32, val);
|
||||
gen_helper_in_func(tcg_ctx, ot, *cpu_T[1], cpu_tmp2_i32);
|
||||
gen_op_mov_reg_v(tcg_ctx, ot, R_EAX, *cpu_T[1]);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
break;
|
||||
case 0xe6:
|
||||
case 0xe7:
|
||||
|
@ -6965,6 +6982,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
tcg_gen_movi_i32(tcg_ctx, cpu_tmp2_i32, val);
|
||||
tcg_gen_trunc_tl_i32(tcg_ctx, cpu_tmp3_i32, *cpu_T[1]);
|
||||
gen_helper_out_func(tcg_ctx, ot, cpu_tmp2_i32, cpu_tmp3_i32);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
break;
|
||||
case 0xec:
|
||||
case 0xed:
|
||||
|
@ -6975,6 +6993,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
tcg_gen_trunc_tl_i32(tcg_ctx, cpu_tmp2_i32, *cpu_T[0]);
|
||||
gen_helper_in_func(tcg_ctx, ot, *cpu_T[1], cpu_tmp2_i32);
|
||||
gen_op_mov_reg_v(tcg_ctx, ot, R_EAX, *cpu_T[1]);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
break;
|
||||
case 0xee:
|
||||
case 0xef:
|
||||
|
@ -6987,6 +7006,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
tcg_gen_trunc_tl_i32(tcg_ctx, cpu_tmp2_i32, *cpu_T[0]);
|
||||
tcg_gen_trunc_tl_i32(tcg_ctx, cpu_tmp3_i32, *cpu_T[1]);
|
||||
gen_helper_out_func(tcg_ctx, ot, cpu_tmp2_i32, cpu_tmp3_i32);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
break;
|
||||
|
||||
/************************/
|
||||
|
|
Loading…
Reference in a new issue