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