Commit f115e911d70dedbbab90efe589b267bf53178f10
1 parent
3ab493de
iret and int fix for vm86 - added undefined instructions for real and vm86 modes…
… - added verr, verrw, arpl - added port io map git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@454 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
142 additions
and
88 deletions
target-i386/translate.c
@@ -749,6 +749,43 @@ static GenOpFunc *gen_op_out_DX_T0[3] = { | @@ -749,6 +749,43 @@ static GenOpFunc *gen_op_out_DX_T0[3] = { | ||
749 | gen_op_outl_DX_T0, | 749 | gen_op_outl_DX_T0, |
750 | }; | 750 | }; |
751 | 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 | + | ||
752 | static inline void gen_movs(DisasContext *s, int ot) | 789 | static inline void gen_movs(DisasContext *s, int ot) |
753 | { | 790 | { |
754 | gen_string_movl_A0_ESI(s); | 791 | gen_string_movl_A0_ESI(s); |
@@ -912,18 +949,6 @@ GEN_REPZ(outs) | @@ -912,18 +949,6 @@ GEN_REPZ(outs) | ||
912 | GEN_REPZ2(scas) | 949 | GEN_REPZ2(scas) |
913 | GEN_REPZ2(cmps) | 950 | GEN_REPZ2(cmps) |
914 | 951 | ||
915 | -static GenOpFunc *gen_op_in[3] = { | ||
916 | - gen_op_inb_T0_T1, | ||
917 | - gen_op_inw_T0_T1, | ||
918 | - gen_op_inl_T0_T1, | ||
919 | -}; | ||
920 | - | ||
921 | -static GenOpFunc *gen_op_out[3] = { | ||
922 | - gen_op_outb_T0_T1, | ||
923 | - gen_op_outw_T0_T1, | ||
924 | - gen_op_outl_T0_T1, | ||
925 | -}; | ||
926 | - | ||
927 | enum { | 952 | enum { |
928 | JCC_O, | 953 | JCC_O, |
929 | JCC_B, | 954 | JCC_B, |
@@ -3221,36 +3246,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3221,36 +3246,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3221 | break; | 3246 | break; |
3222 | case 0x6c: /* insS */ | 3247 | case 0x6c: /* insS */ |
3223 | case 0x6d: | 3248 | case 0x6d: |
3224 | - if (s->pe && (s->cpl > s->iopl || s->vm86)) { | ||
3225 | - /* NOTE: even for (E)CX = 0 the exception is raised */ | ||
3226 | - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 3249 | + if ((b & 1) == 0) |
3250 | + ot = OT_BYTE; | ||
3251 | + 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); | ||
3227 | } else { | 3256 | } else { |
3228 | - if ((b & 1) == 0) | ||
3229 | - ot = OT_BYTE; | ||
3230 | - else | ||
3231 | - ot = dflag ? OT_LONG : OT_WORD; | ||
3232 | - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { | ||
3233 | - gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); | ||
3234 | - } else { | ||
3235 | - gen_ins(s, ot); | ||
3236 | - } | 3257 | + gen_ins(s, ot); |
3237 | } | 3258 | } |
3238 | break; | 3259 | break; |
3239 | case 0x6e: /* outsS */ | 3260 | case 0x6e: /* outsS */ |
3240 | case 0x6f: | 3261 | case 0x6f: |
3241 | - if (s->pe && (s->cpl > s->iopl || s->vm86)) { | ||
3242 | - /* NOTE: even for (E)CX = 0 the exception is raised */ | ||
3243 | - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 3262 | + if ((b & 1) == 0) |
3263 | + ot = OT_BYTE; | ||
3264 | + 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); | ||
3244 | } else { | 3269 | } else { |
3245 | - if ((b & 1) == 0) | ||
3246 | - ot = OT_BYTE; | ||
3247 | - else | ||
3248 | - ot = dflag ? OT_LONG : OT_WORD; | ||
3249 | - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { | ||
3250 | - gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); | ||
3251 | - } else { | ||
3252 | - gen_outs(s, ot); | ||
3253 | - } | 3270 | + gen_outs(s, ot); |
3254 | } | 3271 | } |
3255 | break; | 3272 | break; |
3256 | 3273 | ||
@@ -3258,61 +3275,49 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3258,61 +3275,49 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3258 | /* port I/O */ | 3275 | /* port I/O */ |
3259 | case 0xe4: | 3276 | case 0xe4: |
3260 | case 0xe5: | 3277 | case 0xe5: |
3261 | - if (s->pe && (s->cpl > s->iopl || s->vm86)) { | ||
3262 | - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | ||
3263 | - } else { | ||
3264 | - if ((b & 1) == 0) | ||
3265 | - ot = OT_BYTE; | ||
3266 | - else | ||
3267 | - ot = dflag ? OT_LONG : OT_WORD; | ||
3268 | - val = ldub_code(s->pc++); | ||
3269 | - gen_op_movl_T0_im(val); | ||
3270 | - gen_op_in[ot](); | ||
3271 | - gen_op_mov_reg_T1[ot][R_EAX](); | ||
3272 | - } | 3278 | + if ((b & 1) == 0) |
3279 | + ot = OT_BYTE; | ||
3280 | + else | ||
3281 | + ot = dflag ? OT_LONG : OT_WORD; | ||
3282 | + val = ldub_code(s->pc++); | ||
3283 | + gen_op_movl_T0_im(val); | ||
3284 | + gen_check_io(s, ot, 0, pc_start - s->cs_base); | ||
3285 | + gen_op_in[ot](); | ||
3286 | + gen_op_mov_reg_T1[ot][R_EAX](); | ||
3273 | break; | 3287 | break; |
3274 | case 0xe6: | 3288 | case 0xe6: |
3275 | case 0xe7: | 3289 | case 0xe7: |
3276 | - if (s->pe && (s->cpl > s->iopl || s->vm86)) { | ||
3277 | - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | ||
3278 | - } else { | ||
3279 | - if ((b & 1) == 0) | ||
3280 | - ot = OT_BYTE; | ||
3281 | - else | ||
3282 | - ot = dflag ? OT_LONG : OT_WORD; | ||
3283 | - val = ldub_code(s->pc++); | ||
3284 | - gen_op_movl_T0_im(val); | ||
3285 | - gen_op_mov_TN_reg[ot][1][R_EAX](); | ||
3286 | - gen_op_out[ot](); | ||
3287 | - } | 3290 | + if ((b & 1) == 0) |
3291 | + ot = OT_BYTE; | ||
3292 | + else | ||
3293 | + ot = dflag ? OT_LONG : OT_WORD; | ||
3294 | + val = ldub_code(s->pc++); | ||
3295 | + gen_op_movl_T0_im(val); | ||
3296 | + gen_check_io(s, ot, 0, pc_start - s->cs_base); | ||
3297 | + gen_op_mov_TN_reg[ot][1][R_EAX](); | ||
3298 | + gen_op_out[ot](); | ||
3288 | break; | 3299 | break; |
3289 | case 0xec: | 3300 | case 0xec: |
3290 | case 0xed: | 3301 | case 0xed: |
3291 | - if (s->pe && (s->cpl > s->iopl || s->vm86)) { | ||
3292 | - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | ||
3293 | - } else { | ||
3294 | - if ((b & 1) == 0) | ||
3295 | - ot = OT_BYTE; | ||
3296 | - else | ||
3297 | - ot = dflag ? OT_LONG : OT_WORD; | ||
3298 | - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | ||
3299 | - gen_op_in[ot](); | ||
3300 | - gen_op_mov_reg_T1[ot][R_EAX](); | ||
3301 | - } | 3302 | + if ((b & 1) == 0) |
3303 | + ot = OT_BYTE; | ||
3304 | + else | ||
3305 | + ot = dflag ? OT_LONG : OT_WORD; | ||
3306 | + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | ||
3307 | + gen_check_io(s, ot, 0, pc_start - s->cs_base); | ||
3308 | + gen_op_in[ot](); | ||
3309 | + gen_op_mov_reg_T1[ot][R_EAX](); | ||
3302 | break; | 3310 | break; |
3303 | case 0xee: | 3311 | case 0xee: |
3304 | case 0xef: | 3312 | case 0xef: |
3305 | - if (s->pe && (s->cpl > s->iopl || s->vm86)) { | ||
3306 | - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | ||
3307 | - } else { | ||
3308 | - if ((b & 1) == 0) | ||
3309 | - ot = OT_BYTE; | ||
3310 | - else | ||
3311 | - ot = dflag ? OT_LONG : OT_WORD; | ||
3312 | - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | ||
3313 | - gen_op_mov_TN_reg[ot][1][R_EAX](); | ||
3314 | - gen_op_out[ot](); | ||
3315 | - } | 3313 | + if ((b & 1) == 0) |
3314 | + ot = OT_BYTE; | ||
3315 | + else | ||
3316 | + ot = dflag ? OT_LONG : OT_WORD; | ||
3317 | + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | ||
3318 | + gen_check_io(s, ot, 0, pc_start - s->cs_base); | ||
3319 | + gen_op_mov_TN_reg[ot][1][R_EAX](); | ||
3320 | + gen_op_out[ot](); | ||
3316 | break; | 3321 | break; |
3317 | 3322 | ||
3318 | /************************/ | 3323 | /************************/ |
@@ -3370,8 +3375,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3370,8 +3375,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3370 | /* real mode */ | 3375 | /* real mode */ |
3371 | gen_op_iret_real(s->dflag); | 3376 | gen_op_iret_real(s->dflag); |
3372 | s->cc_op = CC_OP_EFLAGS; | 3377 | s->cc_op = CC_OP_EFLAGS; |
3373 | - } else if (s->vm86 && s->iopl != 3) { | ||
3374 | - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 3378 | + } else if (s->vm86) { |
3379 | + 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 | + } | ||
3375 | } else { | 3385 | } else { |
3376 | if (s->cc_op != CC_OP_DYNAMIC) | 3386 | if (s->cc_op != CC_OP_DYNAMIC) |
3377 | gen_op_set_cc_op(s->cc_op); | 3387 | gen_op_set_cc_op(s->cc_op); |
@@ -3675,11 +3685,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3675,11 +3685,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3675 | break; | 3685 | break; |
3676 | case 0xcd: /* int N */ | 3686 | case 0xcd: /* int N */ |
3677 | val = ldub_code(s->pc++); | 3687 | val = ldub_code(s->pc++); |
3678 | - /* XXX: add error code for vm86 GPF */ | ||
3679 | - if (!s->vm86) | ||
3680 | - gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); | ||
3681 | - else | 3688 | + if (s->vm86 && s->iopl != 3) { |
3682 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 3689 | 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 | + } | ||
3683 | break; | 3693 | break; |
3684 | case 0xce: /* into */ | 3694 | case 0xce: /* into */ |
3685 | if (s->cc_op != CC_OP_DYNAMIC) | 3695 | if (s->cc_op != CC_OP_DYNAMIC) |
@@ -3799,6 +3809,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3799,6 +3809,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3799 | op = (modrm >> 3) & 7; | 3809 | op = (modrm >> 3) & 7; |
3800 | switch(op) { | 3810 | switch(op) { |
3801 | case 0: /* sldt */ | 3811 | case 0: /* sldt */ |
3812 | + if (!s->pe || s->vm86) | ||
3813 | + goto illegal_op; | ||
3802 | gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); | 3814 | gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); |
3803 | ot = OT_WORD; | 3815 | ot = OT_WORD; |
3804 | if (mod == 3) | 3816 | if (mod == 3) |
@@ -3806,6 +3818,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3806,6 +3818,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3806 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); | 3818 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
3807 | break; | 3819 | break; |
3808 | case 2: /* lldt */ | 3820 | case 2: /* lldt */ |
3821 | + if (!s->pe || s->vm86) | ||
3822 | + goto illegal_op; | ||
3809 | if (s->cpl != 0) { | 3823 | if (s->cpl != 0) { |
3810 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 3824 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3811 | } else { | 3825 | } else { |
@@ -3815,6 +3829,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3815,6 +3829,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3815 | } | 3829 | } |
3816 | break; | 3830 | break; |
3817 | case 1: /* str */ | 3831 | case 1: /* str */ |
3832 | + if (!s->pe || s->vm86) | ||
3833 | + goto illegal_op; | ||
3818 | gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); | 3834 | gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); |
3819 | ot = OT_WORD; | 3835 | ot = OT_WORD; |
3820 | if (mod == 3) | 3836 | if (mod == 3) |
@@ -3822,6 +3838,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3822,6 +3838,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3822 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); | 3838 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
3823 | break; | 3839 | break; |
3824 | case 3: /* ltr */ | 3840 | case 3: /* ltr */ |
3841 | + if (!s->pe || s->vm86) | ||
3842 | + goto illegal_op; | ||
3825 | if (s->cpl != 0) { | 3843 | if (s->cpl != 0) { |
3826 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 3844 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3827 | } else { | 3845 | } else { |
@@ -3832,6 +3850,17 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3832,6 +3850,17 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3832 | break; | 3850 | break; |
3833 | case 4: /* verr */ | 3851 | case 4: /* verr */ |
3834 | case 5: /* verw */ | 3852 | 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; | ||
3835 | default: | 3864 | default: |
3836 | goto illegal_op; | 3865 | goto illegal_op; |
3837 | } | 3866 | } |
@@ -3908,6 +3937,31 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3908,6 +3937,31 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3908 | goto illegal_op; | 3937 | goto illegal_op; |
3909 | } | 3938 | } |
3910 | break; | 3939 | 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; | ||
3911 | case 0x102: /* lar */ | 3965 | case 0x102: /* lar */ |
3912 | case 0x103: /* lsl */ | 3966 | case 0x103: /* lsl */ |
3913 | if (!s->pe || s->vm86) | 3967 | if (!s->pe || s->vm86) |