Commit 982b431579c926712633f3d8254bae24b34a4d83

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