| 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) |