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"); | ... | ... |