Commit 982b431579c926712633f3d8254bae24b34a4d83
1 parent
bf7c65bd
added CPL/IOPL support - fixed subtle inc/dec flag optimisation bug - added HLT instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@134 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
112 additions
and
57 deletions
translate-i386.c
... | ... | @@ -130,6 +130,8 @@ typedef struct DisasContext { |
130 | 130 | int addseg; /* non zero if either DS/ES/SS have a non zero base */ |
131 | 131 | int f_st; /* currently unused */ |
132 | 132 | int vm86; /* vm86 mode */ |
133 | + int cpl; | |
134 | + int iopl; | |
133 | 135 | } DisasContext; |
134 | 136 | |
135 | 137 | /* i386 arith/logic operations */ |
... | ... | @@ -2766,26 +2768,36 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2766 | 2768 | break; |
2767 | 2769 | case 0x6c: /* insS */ |
2768 | 2770 | case 0x6d: |
2769 | - if ((b & 1) == 0) | |
2770 | - ot = OT_BYTE; | |
2771 | - else | |
2772 | - ot = dflag ? OT_LONG : OT_WORD; | |
2773 | - if (prefixes & PREFIX_REPZ) { | |
2774 | - gen_string_es(s, ot, gen_op_ins + 9); | |
2771 | + if (s->cpl > s->iopl || s->vm86) { | |
2772 | + /* NOTE: even for (E)CX = 0 the exception is raised */ | |
2773 | + gen_op_gpf(pc_start - s->cs_base); | |
2775 | 2774 | } else { |
2776 | - gen_string_es(s, ot, gen_op_ins); | |
2775 | + if ((b & 1) == 0) | |
2776 | + ot = OT_BYTE; | |
2777 | + else | |
2778 | + ot = dflag ? OT_LONG : OT_WORD; | |
2779 | + if (prefixes & PREFIX_REPZ) { | |
2780 | + gen_string_es(s, ot, gen_op_ins + 9); | |
2781 | + } else { | |
2782 | + gen_string_es(s, ot, gen_op_ins); | |
2783 | + } | |
2777 | 2784 | } |
2778 | 2785 | break; |
2779 | 2786 | case 0x6e: /* outsS */ |
2780 | 2787 | case 0x6f: |
2781 | - if ((b & 1) == 0) | |
2782 | - ot = OT_BYTE; | |
2783 | - else | |
2784 | - ot = dflag ? OT_LONG : OT_WORD; | |
2785 | - if (prefixes & PREFIX_REPZ) { | |
2786 | - gen_string_ds(s, ot, gen_op_outs + 9); | |
2788 | + if (s->cpl > s->iopl || s->vm86) { | |
2789 | + /* NOTE: even for (E)CX = 0 the exception is raised */ | |
2790 | + gen_op_gpf(pc_start - s->cs_base); | |
2787 | 2791 | } else { |
2788 | - gen_string_ds(s, ot, gen_op_outs); | |
2792 | + if ((b & 1) == 0) | |
2793 | + ot = OT_BYTE; | |
2794 | + else | |
2795 | + ot = dflag ? OT_LONG : OT_WORD; | |
2796 | + if (prefixes & PREFIX_REPZ) { | |
2797 | + gen_string_ds(s, ot, gen_op_outs + 9); | |
2798 | + } else { | |
2799 | + gen_string_ds(s, ot, gen_op_outs); | |
2800 | + } | |
2789 | 2801 | } |
2790 | 2802 | break; |
2791 | 2803 | |
... | ... | @@ -2793,45 +2805,61 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2793 | 2805 | /* port I/O */ |
2794 | 2806 | case 0xe4: |
2795 | 2807 | case 0xe5: |
2796 | - if ((b & 1) == 0) | |
2797 | - ot = OT_BYTE; | |
2798 | - else | |
2799 | - ot = dflag ? OT_LONG : OT_WORD; | |
2800 | - val = ldub(s->pc++); | |
2801 | - gen_op_movl_T0_im(val); | |
2802 | - gen_op_in[ot](); | |
2803 | - gen_op_mov_reg_T1[ot][R_EAX](); | |
2808 | + if (s->cpl > s->iopl || s->vm86) { | |
2809 | + gen_op_gpf(pc_start - s->cs_base); | |
2810 | + } else { | |
2811 | + if ((b & 1) == 0) | |
2812 | + ot = OT_BYTE; | |
2813 | + else | |
2814 | + ot = dflag ? OT_LONG : OT_WORD; | |
2815 | + val = ldub(s->pc++); | |
2816 | + gen_op_movl_T0_im(val); | |
2817 | + gen_op_in[ot](); | |
2818 | + gen_op_mov_reg_T1[ot][R_EAX](); | |
2819 | + } | |
2804 | 2820 | break; |
2805 | 2821 | case 0xe6: |
2806 | 2822 | case 0xe7: |
2807 | - if ((b & 1) == 0) | |
2808 | - ot = OT_BYTE; | |
2809 | - else | |
2810 | - ot = dflag ? OT_LONG : OT_WORD; | |
2811 | - val = ldub(s->pc++); | |
2812 | - gen_op_movl_T0_im(val); | |
2813 | - gen_op_mov_TN_reg[ot][1][R_EAX](); | |
2814 | - gen_op_out[ot](); | |
2823 | + if (s->cpl > s->iopl || s->vm86) { | |
2824 | + gen_op_gpf(pc_start - s->cs_base); | |
2825 | + } else { | |
2826 | + if ((b & 1) == 0) | |
2827 | + ot = OT_BYTE; | |
2828 | + else | |
2829 | + ot = dflag ? OT_LONG : OT_WORD; | |
2830 | + val = ldub(s->pc++); | |
2831 | + gen_op_movl_T0_im(val); | |
2832 | + gen_op_mov_TN_reg[ot][1][R_EAX](); | |
2833 | + gen_op_out[ot](); | |
2834 | + } | |
2815 | 2835 | break; |
2816 | 2836 | case 0xec: |
2817 | 2837 | case 0xed: |
2818 | - if ((b & 1) == 0) | |
2819 | - ot = OT_BYTE; | |
2820 | - else | |
2821 | - ot = dflag ? OT_LONG : OT_WORD; | |
2822 | - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | |
2823 | - gen_op_in[ot](); | |
2824 | - gen_op_mov_reg_T1[ot][R_EAX](); | |
2838 | + if (s->cpl > s->iopl || s->vm86) { | |
2839 | + gen_op_gpf(pc_start - s->cs_base); | |
2840 | + } else { | |
2841 | + if ((b & 1) == 0) | |
2842 | + ot = OT_BYTE; | |
2843 | + else | |
2844 | + ot = dflag ? OT_LONG : OT_WORD; | |
2845 | + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | |
2846 | + gen_op_in[ot](); | |
2847 | + gen_op_mov_reg_T1[ot][R_EAX](); | |
2848 | + } | |
2825 | 2849 | break; |
2826 | 2850 | case 0xee: |
2827 | 2851 | case 0xef: |
2828 | - if ((b & 1) == 0) | |
2829 | - ot = OT_BYTE; | |
2830 | - else | |
2831 | - ot = dflag ? OT_LONG : OT_WORD; | |
2832 | - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | |
2833 | - gen_op_mov_TN_reg[ot][1][R_EAX](); | |
2834 | - gen_op_out[ot](); | |
2852 | + if (s->cpl > s->iopl || s->vm86) { | |
2853 | + gen_op_gpf(pc_start - s->cs_base); | |
2854 | + } else { | |
2855 | + if ((b & 1) == 0) | |
2856 | + ot = OT_BYTE; | |
2857 | + else | |
2858 | + ot = dflag ? OT_LONG : OT_WORD; | |
2859 | + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); | |
2860 | + gen_op_mov_TN_reg[ot][1][R_EAX](); | |
2861 | + gen_op_out[ot](); | |
2862 | + } | |
2835 | 2863 | break; |
2836 | 2864 | |
2837 | 2865 | /************************/ |
... | ... | @@ -3219,8 +3247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
3219 | 3247 | break; |
3220 | 3248 | case 0xcd: /* int N */ |
3221 | 3249 | val = ldub(s->pc++); |
3222 | - /* XXX: currently we ignore the interrupt number */ | |
3223 | - gen_op_int_im(pc_start - s->cs_base); | |
3250 | + gen_op_int_im(val, pc_start - s->cs_base); | |
3224 | 3251 | s->is_jmp = 1; |
3225 | 3252 | break; |
3226 | 3253 | case 0xce: /* into */ |
... | ... | @@ -3229,16 +3256,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
3229 | 3256 | gen_op_into(); |
3230 | 3257 | break; |
3231 | 3258 | case 0xfa: /* cli */ |
3232 | - if (s->vm86) | |
3233 | - gen_op_cli_vm(); | |
3234 | - else | |
3235 | - gen_op_cli(); | |
3259 | + if (!s->vm86) { | |
3260 | + if (s->cpl <= s->iopl) | |
3261 | + gen_op_cli(); | |
3262 | + else | |
3263 | + gen_op_gpf(pc_start - s->cs_base); | |
3264 | + } else { | |
3265 | + if (s->iopl == 3) | |
3266 | + gen_op_cli(); | |
3267 | + else | |
3268 | + gen_op_cli_vm(); | |
3269 | + } | |
3236 | 3270 | break; |
3237 | 3271 | case 0xfb: /* sti */ |
3238 | - if (s->vm86) | |
3239 | - gen_op_sti_vm(pc_start - s->cs_base); | |
3240 | - else | |
3241 | - gen_op_sti(); | |
3272 | + if (!s->vm86) { | |
3273 | + if (s->cpl <= s->iopl) | |
3274 | + gen_op_sti(); | |
3275 | + else | |
3276 | + gen_op_gpf(pc_start - s->cs_base); | |
3277 | + } else { | |
3278 | + if (s->iopl == 3) | |
3279 | + gen_op_sti(); | |
3280 | + else | |
3281 | + gen_op_sti_vm(pc_start - s->cs_base); | |
3282 | + } | |
3242 | 3283 | break; |
3243 | 3284 | case 0x62: /* bound */ |
3244 | 3285 | ot = dflag ? OT_LONG : OT_WORD; |
... | ... | @@ -3286,6 +3327,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
3286 | 3327 | case 0x1a2: /* cpuid */ |
3287 | 3328 | gen_op_cpuid(); |
3288 | 3329 | break; |
3330 | + case 0xf4: /* hlt */ | |
3331 | + if (s->cpl == 0) { | |
3332 | + /* ignored */ | |
3333 | + } else { | |
3334 | + gen_op_gpf(pc_start - s->cs_base); | |
3335 | + } | |
3336 | + break; | |
3289 | 3337 | default: |
3290 | 3338 | goto illegal_op; |
3291 | 3339 | } |
... | ... | @@ -3315,6 +3363,10 @@ static uint16_t opc_read_flags[NB_OPS] = { |
3315 | 3363 | [INDEX_op_sbbw_T0_T1_cc] = CC_C, |
3316 | 3364 | [INDEX_op_sbbl_T0_T1_cc] = CC_C, |
3317 | 3365 | |
3366 | + /* subtle: due to the incl/decl implementation, C is used */ | |
3367 | + [INDEX_op_incl_T0_cc] = CC_C, | |
3368 | + [INDEX_op_decl_T0_cc] = CC_C, | |
3369 | + | |
3318 | 3370 | [INDEX_op_into] = CC_O, |
3319 | 3371 | |
3320 | 3372 | [INDEX_op_jo_cc] = CC_O, |
... | ... | @@ -3416,8 +3468,9 @@ static uint16_t opc_write_flags[NB_OPS] = { |
3416 | 3468 | [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC, |
3417 | 3469 | [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, |
3418 | 3470 | [INDEX_op_negl_T0_cc] = CC_OSZAPC, |
3419 | - [INDEX_op_incl_T0_cc] = CC_OSZAP, | |
3420 | - [INDEX_op_decl_T0_cc] = CC_OSZAP, | |
3471 | + /* subtle: due to the incl/decl implementation, C is used */ | |
3472 | + [INDEX_op_incl_T0_cc] = CC_OSZAPC, | |
3473 | + [INDEX_op_decl_T0_cc] = CC_OSZAPC, | |
3421 | 3474 | [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, |
3422 | 3475 | |
3423 | 3476 | [INDEX_op_mulb_AL_T0] = CC_OSZAPC, |
... | ... | @@ -3659,6 +3712,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
3659 | 3712 | dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
3660 | 3713 | dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; |
3661 | 3714 | dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; |
3715 | + dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; | |
3716 | + dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; | |
3662 | 3717 | dc->cc_op = CC_OP_DYNAMIC; |
3663 | 3718 | dc->cs_base = cs_base; |
3664 | 3719 | |
... | ... | @@ -3697,7 +3752,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
3697 | 3752 | disas(logfile, pc_start, pc_ptr - pc_start, |
3698 | 3753 | dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086); |
3699 | 3754 | fprintf(logfile, "\n"); |
3700 | - | |
3755 | + | |
3701 | 3756 | fprintf(logfile, "OP:\n"); |
3702 | 3757 | dump_ops(gen_opc_buf, gen_opparam_buf); |
3703 | 3758 | fprintf(logfile, "\n"); | ... | ... |