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,6 +130,8 @@ typedef struct DisasContext { | ||
130 | int addseg; /* non zero if either DS/ES/SS have a non zero base */ | 130 | int addseg; /* non zero if either DS/ES/SS have a non zero base */ |
131 | int f_st; /* currently unused */ | 131 | int f_st; /* currently unused */ |
132 | int vm86; /* vm86 mode */ | 132 | int vm86; /* vm86 mode */ |
133 | + int cpl; | ||
134 | + int iopl; | ||
133 | } DisasContext; | 135 | } DisasContext; |
134 | 136 | ||
135 | /* i386 arith/logic operations */ | 137 | /* i386 arith/logic operations */ |
@@ -2766,26 +2768,36 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2766,26 +2768,36 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2766 | break; | 2768 | break; |
2767 | case 0x6c: /* insS */ | 2769 | case 0x6c: /* insS */ |
2768 | case 0x6d: | 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 | } else { | 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 | break; | 2785 | break; |
2779 | case 0x6e: /* outsS */ | 2786 | case 0x6e: /* outsS */ |
2780 | case 0x6f: | 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 | } else { | 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 | break; | 2802 | break; |
2791 | 2803 | ||
@@ -2793,45 +2805,61 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2793,45 +2805,61 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2793 | /* port I/O */ | 2805 | /* port I/O */ |
2794 | case 0xe4: | 2806 | case 0xe4: |
2795 | case 0xe5: | 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 | break; | 2820 | break; |
2805 | case 0xe6: | 2821 | case 0xe6: |
2806 | case 0xe7: | 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 | break; | 2835 | break; |
2816 | case 0xec: | 2836 | case 0xec: |
2817 | case 0xed: | 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 | break; | 2849 | break; |
2826 | case 0xee: | 2850 | case 0xee: |
2827 | case 0xef: | 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 | break; | 2863 | break; |
2836 | 2864 | ||
2837 | /************************/ | 2865 | /************************/ |
@@ -3219,8 +3247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3219,8 +3247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3219 | break; | 3247 | break; |
3220 | case 0xcd: /* int N */ | 3248 | case 0xcd: /* int N */ |
3221 | val = ldub(s->pc++); | 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 | s->is_jmp = 1; | 3251 | s->is_jmp = 1; |
3225 | break; | 3252 | break; |
3226 | case 0xce: /* into */ | 3253 | case 0xce: /* into */ |
@@ -3229,16 +3256,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3229,16 +3256,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3229 | gen_op_into(); | 3256 | gen_op_into(); |
3230 | break; | 3257 | break; |
3231 | case 0xfa: /* cli */ | 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 | break; | 3270 | break; |
3237 | case 0xfb: /* sti */ | 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 | break; | 3283 | break; |
3243 | case 0x62: /* bound */ | 3284 | case 0x62: /* bound */ |
3244 | ot = dflag ? OT_LONG : OT_WORD; | 3285 | ot = dflag ? OT_LONG : OT_WORD; |
@@ -3286,6 +3327,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3286,6 +3327,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3286 | case 0x1a2: /* cpuid */ | 3327 | case 0x1a2: /* cpuid */ |
3287 | gen_op_cpuid(); | 3328 | gen_op_cpuid(); |
3288 | break; | 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 | default: | 3337 | default: |
3290 | goto illegal_op; | 3338 | goto illegal_op; |
3291 | } | 3339 | } |
@@ -3315,6 +3363,10 @@ static uint16_t opc_read_flags[NB_OPS] = { | @@ -3315,6 +3363,10 @@ static uint16_t opc_read_flags[NB_OPS] = { | ||
3315 | [INDEX_op_sbbw_T0_T1_cc] = CC_C, | 3363 | [INDEX_op_sbbw_T0_T1_cc] = CC_C, |
3316 | [INDEX_op_sbbl_T0_T1_cc] = CC_C, | 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 | [INDEX_op_into] = CC_O, | 3370 | [INDEX_op_into] = CC_O, |
3319 | 3371 | ||
3320 | [INDEX_op_jo_cc] = CC_O, | 3372 | [INDEX_op_jo_cc] = CC_O, |
@@ -3416,8 +3468,9 @@ static uint16_t opc_write_flags[NB_OPS] = { | @@ -3416,8 +3468,9 @@ static uint16_t opc_write_flags[NB_OPS] = { | ||
3416 | [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC, | 3468 | [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC, |
3417 | [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, | 3469 | [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, |
3418 | [INDEX_op_negl_T0_cc] = CC_OSZAPC, | 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 | [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, | 3474 | [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, |
3422 | 3475 | ||
3423 | [INDEX_op_mulb_AL_T0] = CC_OSZAPC, | 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,6 +3712,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
3659 | dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; | 3712 | dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
3660 | dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; | 3713 | dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; |
3661 | dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; | 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 | dc->cc_op = CC_OP_DYNAMIC; | 3717 | dc->cc_op = CC_OP_DYNAMIC; |
3663 | dc->cs_base = cs_base; | 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,7 +3752,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
3697 | disas(logfile, pc_start, pc_ptr - pc_start, | 3752 | disas(logfile, pc_start, pc_ptr - pc_start, |
3698 | dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086); | 3753 | dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086); |
3699 | fprintf(logfile, "\n"); | 3754 | fprintf(logfile, "\n"); |
3700 | - | 3755 | + |
3701 | fprintf(logfile, "OP:\n"); | 3756 | fprintf(logfile, "OP:\n"); |
3702 | dump_ops(gen_opc_buf, gen_opparam_buf); | 3757 | dump_ops(gen_opc_buf, gen_opparam_buf); |
3703 | fprintf(logfile, "\n"); | 3758 | fprintf(logfile, "\n"); |