749 |
gen_op_outl_DX_T0, |
gen_op_outl_DX_T0, |
750 |
}; |
}; |
751 |
|
|
752 |
|
static GenOpFunc *gen_op_in[3] = { |
753 |
|
gen_op_inb_T0_T1, |
754 |
|
gen_op_inw_T0_T1, |
755 |
|
gen_op_inl_T0_T1, |
756 |
|
}; |
757 |
|
|
758 |
|
static GenOpFunc *gen_op_out[3] = { |
759 |
|
gen_op_outb_T0_T1, |
760 |
|
gen_op_outw_T0_T1, |
761 |
|
gen_op_outl_T0_T1, |
762 |
|
}; |
763 |
|
|
764 |
|
static GenOpFunc *gen_check_io_T0[3] = { |
765 |
|
gen_op_check_iob_T0, |
766 |
|
gen_op_check_iow_T0, |
767 |
|
gen_op_check_iol_T0, |
768 |
|
}; |
769 |
|
|
770 |
|
static GenOpFunc *gen_check_io_DX[3] = { |
771 |
|
gen_op_check_iob_DX, |
772 |
|
gen_op_check_iow_DX, |
773 |
|
gen_op_check_iol_DX, |
774 |
|
}; |
775 |
|
|
776 |
|
static void gen_check_io(DisasContext *s, int ot, int use_dx, int cur_eip) |
777 |
|
{ |
778 |
|
if (s->pe && (s->cpl > s->iopl || s->vm86)) { |
779 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
780 |
|
gen_op_set_cc_op(s->cc_op); |
781 |
|
gen_op_jmp_im(cur_eip); |
782 |
|
if (use_dx) |
783 |
|
gen_check_io_DX[ot](); |
784 |
|
else |
785 |
|
gen_check_io_T0[ot](); |
786 |
|
} |
787 |
|
} |
788 |
|
|
789 |
static inline void gen_movs(DisasContext *s, int ot) |
static inline void gen_movs(DisasContext *s, int ot) |
790 |
{ |
{ |
791 |
gen_string_movl_A0_ESI(s); |
gen_string_movl_A0_ESI(s); |
949 |
GEN_REPZ2(scas) |
GEN_REPZ2(scas) |
950 |
GEN_REPZ2(cmps) |
GEN_REPZ2(cmps) |
951 |
|
|
|
static GenOpFunc *gen_op_in[3] = { |
|
|
gen_op_inb_T0_T1, |
|
|
gen_op_inw_T0_T1, |
|
|
gen_op_inl_T0_T1, |
|
|
}; |
|
|
|
|
|
static GenOpFunc *gen_op_out[3] = { |
|
|
gen_op_outb_T0_T1, |
|
|
gen_op_outw_T0_T1, |
|
|
gen_op_outl_T0_T1, |
|
|
}; |
|
|
|
|
952 |
enum { |
enum { |
953 |
JCC_O, |
JCC_O, |
954 |
JCC_B, |
JCC_B, |
3246 |
break; |
break; |
3247 |
case 0x6c: /* insS */ |
case 0x6c: /* insS */ |
3248 |
case 0x6d: |
case 0x6d: |
3249 |
if (s->pe && (s->cpl > s->iopl || s->vm86)) { |
if ((b & 1) == 0) |
3250 |
/* NOTE: even for (E)CX = 0 the exception is raised */ |
ot = OT_BYTE; |
3251 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
else |
3252 |
|
ot = dflag ? OT_LONG : OT_WORD; |
3253 |
|
gen_check_io(s, ot, 1, pc_start - s->cs_base); |
3254 |
|
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
3255 |
|
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
3256 |
} else { |
} else { |
3257 |
if ((b & 1) == 0) |
gen_ins(s, ot); |
|
ot = OT_BYTE; |
|
|
else |
|
|
ot = dflag ? OT_LONG : OT_WORD; |
|
|
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
|
|
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
|
|
} else { |
|
|
gen_ins(s, ot); |
|
|
} |
|
3258 |
} |
} |
3259 |
break; |
break; |
3260 |
case 0x6e: /* outsS */ |
case 0x6e: /* outsS */ |
3261 |
case 0x6f: |
case 0x6f: |
3262 |
if (s->pe && (s->cpl > s->iopl || s->vm86)) { |
if ((b & 1) == 0) |
3263 |
/* NOTE: even for (E)CX = 0 the exception is raised */ |
ot = OT_BYTE; |
3264 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
else |
3265 |
|
ot = dflag ? OT_LONG : OT_WORD; |
3266 |
|
gen_check_io(s, ot, 1, pc_start - s->cs_base); |
3267 |
|
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
3268 |
|
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
3269 |
} else { |
} else { |
3270 |
if ((b & 1) == 0) |
gen_outs(s, ot); |
|
ot = OT_BYTE; |
|
|
else |
|
|
ot = dflag ? OT_LONG : OT_WORD; |
|
|
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
|
|
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
|
|
} else { |
|
|
gen_outs(s, ot); |
|
|
} |
|
3271 |
} |
} |
3272 |
break; |
break; |
3273 |
|
|
3275 |
/* port I/O */ |
/* port I/O */ |
3276 |
case 0xe4: |
case 0xe4: |
3277 |
case 0xe5: |
case 0xe5: |
3278 |
if (s->pe && (s->cpl > s->iopl || s->vm86)) { |
if ((b & 1) == 0) |
3279 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
ot = OT_BYTE; |
3280 |
} else { |
else |
3281 |
if ((b & 1) == 0) |
ot = dflag ? OT_LONG : OT_WORD; |
3282 |
ot = OT_BYTE; |
val = ldub_code(s->pc++); |
3283 |
else |
gen_op_movl_T0_im(val); |
3284 |
ot = dflag ? OT_LONG : OT_WORD; |
gen_check_io(s, ot, 0, pc_start - s->cs_base); |
3285 |
val = ldub_code(s->pc++); |
gen_op_in[ot](); |
3286 |
gen_op_movl_T0_im(val); |
gen_op_mov_reg_T1[ot][R_EAX](); |
|
gen_op_in[ot](); |
|
|
gen_op_mov_reg_T1[ot][R_EAX](); |
|
|
} |
|
3287 |
break; |
break; |
3288 |
case 0xe6: |
case 0xe6: |
3289 |
case 0xe7: |
case 0xe7: |
3290 |
if (s->pe && (s->cpl > s->iopl || s->vm86)) { |
if ((b & 1) == 0) |
3291 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
ot = OT_BYTE; |
3292 |
} else { |
else |
3293 |
if ((b & 1) == 0) |
ot = dflag ? OT_LONG : OT_WORD; |
3294 |
ot = OT_BYTE; |
val = ldub_code(s->pc++); |
3295 |
else |
gen_op_movl_T0_im(val); |
3296 |
ot = dflag ? OT_LONG : OT_WORD; |
gen_check_io(s, ot, 0, pc_start - s->cs_base); |
3297 |
val = ldub_code(s->pc++); |
gen_op_mov_TN_reg[ot][1][R_EAX](); |
3298 |
gen_op_movl_T0_im(val); |
gen_op_out[ot](); |
|
gen_op_mov_TN_reg[ot][1][R_EAX](); |
|
|
gen_op_out[ot](); |
|
|
} |
|
3299 |
break; |
break; |
3300 |
case 0xec: |
case 0xec: |
3301 |
case 0xed: |
case 0xed: |
3302 |
if (s->pe && (s->cpl > s->iopl || s->vm86)) { |
if ((b & 1) == 0) |
3303 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
ot = OT_BYTE; |
3304 |
} else { |
else |
3305 |
if ((b & 1) == 0) |
ot = dflag ? OT_LONG : OT_WORD; |
3306 |
ot = OT_BYTE; |
gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); |
3307 |
else |
gen_check_io(s, ot, 0, pc_start - s->cs_base); |
3308 |
ot = dflag ? OT_LONG : OT_WORD; |
gen_op_in[ot](); |
3309 |
gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); |
gen_op_mov_reg_T1[ot][R_EAX](); |
|
gen_op_in[ot](); |
|
|
gen_op_mov_reg_T1[ot][R_EAX](); |
|
|
} |
|
3310 |
break; |
break; |
3311 |
case 0xee: |
case 0xee: |
3312 |
case 0xef: |
case 0xef: |
3313 |
if (s->pe && (s->cpl > s->iopl || s->vm86)) { |
if ((b & 1) == 0) |
3314 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
ot = OT_BYTE; |
3315 |
} else { |
else |
3316 |
if ((b & 1) == 0) |
ot = dflag ? OT_LONG : OT_WORD; |
3317 |
ot = OT_BYTE; |
gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); |
3318 |
else |
gen_check_io(s, ot, 0, pc_start - s->cs_base); |
3319 |
ot = dflag ? OT_LONG : OT_WORD; |
gen_op_mov_TN_reg[ot][1][R_EAX](); |
3320 |
gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); |
gen_op_out[ot](); |
|
gen_op_mov_TN_reg[ot][1][R_EAX](); |
|
|
gen_op_out[ot](); |
|
|
} |
|
3321 |
break; |
break; |
3322 |
|
|
3323 |
/************************/ |
/************************/ |
3375 |
/* real mode */ |
/* real mode */ |
3376 |
gen_op_iret_real(s->dflag); |
gen_op_iret_real(s->dflag); |
3377 |
s->cc_op = CC_OP_EFLAGS; |
s->cc_op = CC_OP_EFLAGS; |
3378 |
} else if (s->vm86 && s->iopl != 3) { |
} else if (s->vm86) { |
3379 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
if (s->iopl != 3) { |
3380 |
|
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3381 |
|
} else { |
3382 |
|
gen_op_iret_real(s->dflag); |
3383 |
|
s->cc_op = CC_OP_EFLAGS; |
3384 |
|
} |
3385 |
} else { |
} else { |
3386 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
3387 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
3685 |
break; |
break; |
3686 |
case 0xcd: /* int N */ |
case 0xcd: /* int N */ |
3687 |
val = ldub_code(s->pc++); |
val = ldub_code(s->pc++); |
3688 |
/* XXX: add error code for vm86 GPF */ |
if (s->vm86 && s->iopl != 3) { |
|
if (!s->vm86) |
|
|
gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); |
|
|
else |
|
3689 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3690 |
|
} else { |
3691 |
|
gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); |
3692 |
|
} |
3693 |
break; |
break; |
3694 |
case 0xce: /* into */ |
case 0xce: /* into */ |
3695 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
3809 |
op = (modrm >> 3) & 7; |
op = (modrm >> 3) & 7; |
3810 |
switch(op) { |
switch(op) { |
3811 |
case 0: /* sldt */ |
case 0: /* sldt */ |
3812 |
|
if (!s->pe || s->vm86) |
3813 |
|
goto illegal_op; |
3814 |
gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); |
gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); |
3815 |
ot = OT_WORD; |
ot = OT_WORD; |
3816 |
if (mod == 3) |
if (mod == 3) |
3818 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
3819 |
break; |
break; |
3820 |
case 2: /* lldt */ |
case 2: /* lldt */ |
3821 |
|
if (!s->pe || s->vm86) |
3822 |
|
goto illegal_op; |
3823 |
if (s->cpl != 0) { |
if (s->cpl != 0) { |
3824 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3825 |
} else { |
} else { |
3829 |
} |
} |
3830 |
break; |
break; |
3831 |
case 1: /* str */ |
case 1: /* str */ |
3832 |
|
if (!s->pe || s->vm86) |
3833 |
|
goto illegal_op; |
3834 |
gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); |
gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); |
3835 |
ot = OT_WORD; |
ot = OT_WORD; |
3836 |
if (mod == 3) |
if (mod == 3) |
3838 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
3839 |
break; |
break; |
3840 |
case 3: /* ltr */ |
case 3: /* ltr */ |
3841 |
|
if (!s->pe || s->vm86) |
3842 |
|
goto illegal_op; |
3843 |
if (s->cpl != 0) { |
if (s->cpl != 0) { |
3844 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3845 |
} else { |
} else { |
3850 |
break; |
break; |
3851 |
case 4: /* verr */ |
case 4: /* verr */ |
3852 |
case 5: /* verw */ |
case 5: /* verw */ |
3853 |
|
if (!s->pe || s->vm86) |
3854 |
|
goto illegal_op; |
3855 |
|
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); |
3856 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
3857 |
|
gen_op_set_cc_op(s->cc_op); |
3858 |
|
if (op == 4) |
3859 |
|
gen_op_verr(); |
3860 |
|
else |
3861 |
|
gen_op_verw(); |
3862 |
|
s->cc_op = CC_OP_EFLAGS; |
3863 |
|
break; |
3864 |
default: |
default: |
3865 |
goto illegal_op; |
goto illegal_op; |
3866 |
} |
} |
3937 |
goto illegal_op; |
goto illegal_op; |
3938 |
} |
} |
3939 |
break; |
break; |
3940 |
|
case 0x63: /* arpl */ |
3941 |
|
if (!s->pe || s->vm86) |
3942 |
|
goto illegal_op; |
3943 |
|
ot = dflag ? OT_LONG : OT_WORD; |
3944 |
|
modrm = ldub_code(s->pc++); |
3945 |
|
reg = (modrm >> 3) & 7; |
3946 |
|
mod = (modrm >> 6) & 3; |
3947 |
|
rm = modrm & 7; |
3948 |
|
if (mod != 3) { |
3949 |
|
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3950 |
|
gen_op_ld_T0_A0[ot + s->mem_index](); |
3951 |
|
} else { |
3952 |
|
gen_op_mov_TN_reg[ot][0][rm](); |
3953 |
|
} |
3954 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
3955 |
|
gen_op_set_cc_op(s->cc_op); |
3956 |
|
gen_op_arpl(); |
3957 |
|
s->cc_op = CC_OP_EFLAGS; |
3958 |
|
if (mod != 3) { |
3959 |
|
gen_op_st_T0_A0[ot + s->mem_index](); |
3960 |
|
} else { |
3961 |
|
gen_op_mov_reg_T0[ot][rm](); |
3962 |
|
} |
3963 |
|
gen_op_arpl_update(); |
3964 |
|
break; |
3965 |
case 0x102: /* lar */ |
case 0x102: /* lar */ |
3966 |
case 0x103: /* lsl */ |
case 0x103: /* lsl */ |
3967 |
if (!s->pe || s->vm86) |
if (!s->pe || s->vm86) |