#define IN_OP_I386
#include "cpu-i386.h"
-#ifndef offsetof
-#define offsetof(type, field) ((size_t) &((type *)0)->field)
-#endif
-
/* XXX: move that elsewhere */
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
int vm86; /* vm86 mode */
int cpl;
int iopl;
+ int tf; /* TF cpu flag */
} DisasContext;
/* i386 arith/logic operations */
gen_op_mov_reg_T1[ot][R_ESP]();
}
+static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip)
+{
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_jmp_im(cur_eip);
+ gen_op_raise_exception(trapno);
+ s->is_jmp = 1;
+}
+
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
is set to true if the instruction sets the PC (last instruction of
a basic block) */
case 0x6d:
if (s->cpl > s->iopl || s->vm86) {
/* NOTE: even for (E)CX = 0 the exception is raised */
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
if ((b & 1) == 0)
ot = OT_BYTE;
case 0x6f:
if (s->cpl > s->iopl || s->vm86) {
/* NOTE: even for (E)CX = 0 the exception is raised */
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
if ((b & 1) == 0)
ot = OT_BYTE;
case 0xe4:
case 0xe5:
if (s->cpl > s->iopl || s->vm86) {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
if ((b & 1) == 0)
ot = OT_BYTE;
case 0xe6:
case 0xe7:
if (s->cpl > s->iopl || s->vm86) {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
if ((b & 1) == 0)
ot = OT_BYTE;
case 0xec:
case 0xed:
if (s->cpl > s->iopl || s->vm86) {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
if ((b & 1) == 0)
ot = OT_BYTE;
case 0xee:
case 0xef:
if (s->cpl > s->iopl || s->vm86) {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
if ((b & 1) == 0)
ot = OT_BYTE;
break;
case 0xcf: /* iret */
if (s->vm86 && s->iopl != 3) {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
/* XXX: not restartable */
/* pop offset */
/* flags */
case 0x9c: /* pushf */
if (s->vm86 && s->iopl != 3) {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
break;
case 0x9d: /* popf */
if (s->vm86 && s->iopl != 3) {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_pop_T0(s);
if (s->dflag) {
}
gen_pop_update(s);
s->cc_op = CC_OP_EFLAGS;
+ s->is_jmp = 2; /* abort translation because TF flag may change */
}
break;
case 0x9e: /* sahf */
case 0x90: /* nop */
break;
case 0xcc: /* int3 */
- gen_op_int3((long)pc_start);
- s->is_jmp = 1;
+ gen_exception(s, EXCP03_INT3, s->pc - s->cs_base);
break;
case 0xcd: /* int N */
val = ldub(s->pc++);
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
gen_op_int_im(val, pc_start - s->cs_base);
s->is_jmp = 1;
break;
case 0xce: /* into */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_op_into();
+ gen_op_into(s->pc - s->cs_base);
break;
case 0xfa: /* cli */
if (!s->vm86) {
if (s->cpl <= s->iopl) {
gen_op_cli();
} else {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
} else {
if (s->iopl == 3) {
gen_op_cli();
} else {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
}
break;
if (s->cpl <= s->iopl) {
gen_op_sti();
} else {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
} else {
if (s->iopl == 3) {
gen_op_sti();
} else {
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
}
break;
break;
case 0xf4: /* hlt */
/* XXX: if cpl == 0, then should do something else */
- gen_op_gpf(pc_start - s->cs_base);
- s->is_jmp = 1;
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ case 0x102: /* lar */
+ case 0x103: /* lsl */
+ if (s->vm86)
+ goto illegal_op;
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ reg = (modrm >> 3) & 7;
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+ gen_op_mov_TN_reg[ot][1][reg]();
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ if (b == 0x102)
+ gen_op_lar();
+ else
+ gen_op_lsl();
+ s->cc_op = CC_OP_EFLAGS;
+ gen_op_mov_reg_T1[ot][reg]();
break;
default:
goto illegal_op;
[INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
[INDEX_op_movl_T0_eflags] = CC_OSZAPC,
- [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC,
[INDEX_op_cmc] = CC_C,
[INDEX_op_salc] = CC_C,
[INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
[INDEX_op_movw_eflags_T0] = CC_OSZAPC,
- [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC,
[INDEX_op_movl_eflags_T0] = CC_OSZAPC,
- [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC,
[INDEX_op_clc] = CC_C,
[INDEX_op_stc] = CC_C,
[INDEX_op_cmc] = CC_C,
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchg8b] = CC_Z,
+ [INDEX_op_lar] = CC_Z,
+ [INDEX_op_lsl] = CC_Z,
};
/* simpler form of an operation if no flags need to be generated */
for(;;) {
c = *opc_ptr++;
n = op_nb_args[c];
- fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]);
+ fprintf(logfile, "0x%04x: %s",
+ (int)(opc_ptr - opc_buf - 1), op_str[c]);
for(i = 0; i < n; i++) {
fprintf(logfile, " 0x%x", opparam_ptr[i]);
}
static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
/* return non zero if the very first instruction is invalid so that
- the virtual CPU can trigger an exception. */
+ the virtual CPU can trigger an exception.
+
+ '*code_size_ptr' contains the target code size including the
+ instruction which triggered an exception, except in case of invalid
+ illegal opcode. It must never exceed one target page.
+
+ '*gen_code_size_ptr' contains the size of the generated code (host
+ code).
+*/
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr,
- uint8_t *pc_start, uint8_t *cs_base, int flags)
+ uint8_t *pc_start, uint8_t *cs_base, int flags,
+ int *code_size_ptr)
{
DisasContext dc1, *dc = &dc1;
uint8_t *pc_ptr;
dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1;
dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3;
dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3;
+ dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1;
dc->cc_op = CC_OP_DYNAMIC;
dc->cs_base = cs_base;
break;
}
pc_ptr = (void *)ret;
- } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end);
+ /* if single step mode, we generate only one instruction and
+ generate an exception */
+ if (dc->tf)
+ break;
+ } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
+ (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
/* we must store the eflags state if it is not already done */
if (dc->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(dc->cc_op);
/* we add an additionnal jmp to update the simulated PC */
gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
}
+ if (dc->tf) {
+ gen_op_raise_exception(EXCP01_SSTP);
+ }
+
*gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf);
flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size));
*gen_code_size_ptr = gen_code_size;
-
+ *code_size_ptr = pc_ptr - pc_start;
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
if (!inited) {
inited = 1;
optimize_flags_init();
+ page_init();
}
return env;
}