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 | 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 | 789 | static inline void gen_movs(DisasContext *s, int ot) |
753 | 790 | { |
754 | 791 | gen_string_movl_A0_ESI(s); |
... | ... | @@ -912,18 +949,6 @@ GEN_REPZ(outs) |
912 | 949 | GEN_REPZ2(scas) |
913 | 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 | 952 | enum { |
928 | 953 | JCC_O, |
929 | 954 | JCC_B, |
... | ... | @@ -3221,36 +3246,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3221 | 3246 | break; |
3222 | 3247 | case 0x6c: /* insS */ |
3223 | 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 | 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 | 3259 | break; |
3239 | 3260 | case 0x6e: /* outsS */ |
3240 | 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 | 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 | 3272 | break; |
3256 | 3273 | |
... | ... | @@ -3258,61 +3275,49 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3258 | 3275 | /* port I/O */ |
3259 | 3276 | case 0xe4: |
3260 | 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 | 3287 | break; |
3274 | 3288 | case 0xe6: |
3275 | 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 | 3299 | break; |
3289 | 3300 | case 0xec: |
3290 | 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 | 3310 | break; |
3303 | 3311 | case 0xee: |
3304 | 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 | 3321 | break; |
3317 | 3322 | |
3318 | 3323 | /************************/ |
... | ... | @@ -3370,8 +3375,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3370 | 3375 | /* real mode */ |
3371 | 3376 | gen_op_iret_real(s->dflag); |
3372 | 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 | 3385 | } else { |
3376 | 3386 | if (s->cc_op != CC_OP_DYNAMIC) |
3377 | 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 | 3685 | break; |
3676 | 3686 | case 0xcd: /* int N */ |
3677 | 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 | 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 | 3693 | break; |
3684 | 3694 | case 0xce: /* into */ |
3685 | 3695 | if (s->cc_op != CC_OP_DYNAMIC) |
... | ... | @@ -3799,6 +3809,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3799 | 3809 | op = (modrm >> 3) & 7; |
3800 | 3810 | switch(op) { |
3801 | 3811 | case 0: /* sldt */ |
3812 | + if (!s->pe || s->vm86) | |
3813 | + goto illegal_op; | |
3802 | 3814 | gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); |
3803 | 3815 | ot = OT_WORD; |
3804 | 3816 | if (mod == 3) |
... | ... | @@ -3806,6 +3818,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3806 | 3818 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
3807 | 3819 | break; |
3808 | 3820 | case 2: /* lldt */ |
3821 | + if (!s->pe || s->vm86) | |
3822 | + goto illegal_op; | |
3809 | 3823 | if (s->cpl != 0) { |
3810 | 3824 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3811 | 3825 | } else { |
... | ... | @@ -3815,6 +3829,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3815 | 3829 | } |
3816 | 3830 | break; |
3817 | 3831 | case 1: /* str */ |
3832 | + if (!s->pe || s->vm86) | |
3833 | + goto illegal_op; | |
3818 | 3834 | gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); |
3819 | 3835 | ot = OT_WORD; |
3820 | 3836 | if (mod == 3) |
... | ... | @@ -3822,6 +3838,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3822 | 3838 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
3823 | 3839 | break; |
3824 | 3840 | case 3: /* ltr */ |
3841 | + if (!s->pe || s->vm86) | |
3842 | + goto illegal_op; | |
3825 | 3843 | if (s->cpl != 0) { |
3826 | 3844 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3827 | 3845 | } else { |
... | ... | @@ -3832,6 +3850,17 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3832 | 3850 | break; |
3833 | 3851 | case 4: /* verr */ |
3834 | 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 | 3864 | default: |
3836 | 3865 | goto illegal_op; |
3837 | 3866 | } |
... | ... | @@ -3908,6 +3937,31 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
3908 | 3937 | goto illegal_op; |
3909 | 3938 | } |
3910 | 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 | 3965 | case 0x102: /* lar */ |
3912 | 3966 | case 0x103: /* lsl */ |
3913 | 3967 | if (!s->pe || s->vm86) | ... | ... |